Java学习7
心情有问题,兴致不高
this
1.this 是一个关键字,全部小写2.this是一个变量,是一个引用一个对象一个this,this保存当前对象的内存地址,指向自身所以,严格意义上来说,this代表的就是“当前对象”this存储在堆内存中,存储在对象的内部3.this只能使用在实例方法中,谁调用这个实例方法,this就是谁,所以this代表的是:当前对象4. this. 大部分情况下可以省略,省略了还是默认访问当前对象5. this 代表当前对象,而静态方法的调用不需要对象,矛盾了,所以在静态方法中无法使用this6. 在实例方法和构造方法中,为了区别实例变量和局部变量,这种情况下,this.不能省略7. this除了用在实例方法中,还可以用在构造方法中新语法:通过当前的构造方法1去调用本类另一个的构造方法2,可以做到代码复用,可以使用以下语法格式:this(实际参数列表);对于this()的调用只能使用一次,并且只能出现在构造方法的第一行
如果方法中直接访问了实例变量,该方法必须是实例方法
总结
到目前为止一个类中可以出现的:
类体{
实例变量;
实例方法;
静态变量;
静态方法;
构造方法;
静态代码块;
实例语句块;
方法(){
局部变量;
}
}
类加载机制是这样的:在程序执行之前,凡是需要加载的类全部加载到JVM当中,先完成加载才会执行main方法
所有的实例相关的都是先创建对象,通过“引用.”来访问
所有的静态相关的都是直接采用“类名.”来访问
只要负责调用的方法a和被调用的方法b在同一个类当中:
this. 可以省略
类名. 可以省略
当类的字节码文件被加载到内存时,类的实例方法不会被分配入口地址
当该类创建对象后,类中的实例方法才分配入口地址,
从而实例方法可以被类创建的任何对象调用执行。
类方法在该类被加载到内存时,就分配了相应的入口地址。
从而类方法不仅可以被类创建的任何对象调用执行,也可以直接通过类名调用。
类方法的入口地址直到程序退出时才被取消。
当我们创建第一个对象时,类中的实例方法就分配了入口地址,当再创建对象时,不再分配入口地址。
也就是说,方法的入口地址被所有的对象共享,当所有的对象都不存在时,方法的入口地址才被取消。
在Java语言中,类中的类方法不可以操作实例变量,也不可以调用实例方法,
这是因为在类创建对象之前,实例成员变量还没有分配内存,而且实例方法也没有入口地址。
继承(extends)
继承的作用:
基本作用:子类继承父类,代码可以得到复用
主要(重要)作用:因为有了继承关系,才有了后期的方法覆盖和多态机制class A{}
class B extends A{}继承的相关特性:
1.B类继承A类,则A类为超类(superclass)、父类、基类,
B类则成为子类(subclass)、派生类、扩展类。
2. java中只支持单继承,不允许多继承,但有的时候会产生间接继承的效果
即class C extends A,B 不允许,但是允许class C extends B,class B extends A
3. java中规定,子类继承父类,除构造方法不能继承之外,剩下的都可以继承,但是私有的属性无法在子类中直接访问(父类中private修饰的不能在子类中直接访问,可以通过间接的手段来访问)
4. java中的类,没有显示的继承任何类,则默认继承Object类,Object类是java语言提供的根类(老祖宗类),也就是说,一个对象与生俱来就有Object中所有的特征
5. 继承存在一些缺点,即父类和子类的耦合度非常高,父类修改会使子类受到牵连
什么时候使用继承?
凡是采用“is a”能描述的,都可以继承
例如: Dog is a Animal; CreditAccount is a Account
Object
java为什么比较好学?
是因为java内置了一套庞大的类库,实现了很多基本的功能,程序员不需要从0开始写代码,程序员可以基于这套庞大的类库进行“二次开发”
System.out.println(“Hello World”);
System是一个类,直接使用类名System.out,out后面没有括号,说明out是一个静态变量。
Syetem.out返回一个对象,然后采用“对象.”的方式访问println()方法;
当源码当中一个方法以“;”结尾,并且修饰符列表中有“native”关键字,表示底层调用C++写的dll程序(dll动态链接库文件)
大部分Object中的方法看不懂,其中有一个叫做toString,是把对象转化成字符串,
经测试发现System.out.println(引用),当直接输出引用的时候,println()方法会先自动调用“引用.toString”,然后输出toString()方法的执行结果,输出结果为:
- 类名@16进制的地址
这个地址可以看做是对象在堆内存当中的内存地址,实际上是内存地址经过“哈希算法”得出的十六进制结果
方法重写、覆盖(Override)
也可以叫overwrite
子类继承父类中,有一些“行为”可能不需要改进,有一些“行为”可能面临需要改进,因为父类中继承过来的方法已经不能满足子类的业务需求回顾方法重载overload:
当在一个类中,如果功能相似的话,建议将名字定义为一样,这样代码美观,并且方便编程进行方法重写时,最好将父类的方法原封不动的复制过来(不建议手动编写)
方法覆盖后,子类对象调用该方法的时候, 一定执行覆盖之后的方法在代码级别上怎么构成方法覆盖?
条件一:两个类必须要有继承关系
条件二:重写之后的方法必须和之前的方法具有相同的方法名、返回值类型、参数列表
条件三:访问权限不能更低,可以更高
protected表示受保护的,没有public开放,所以用protected去修饰的方法覆盖public修饰的方法时,会报错
条件四:重写之后的方法不能比之前的方法抛出更多的异常,可以更少
条件五:对于返回值类型是基本数据类型来说,必须一致;
对于返回值类型引用数据类型,子类中重写之后的返回值类型变小,编译可以通过,但意义不大;反之不行(没有用,一般方法重写都是复制粘贴)注意1:方法覆盖只是针对于方法,和属性无关
注意2:私有方法无法覆盖
注意3:构造方法不能被继承,所以构造方法也不能够被覆盖
注意4:方法覆盖只针对于“实例方法”,“静态方法覆盖”没有意义(这是因为方法覆盖通常是和多态联合起来)关于Object类中toString()方法的覆盖?
toString()方法存在的作用就是:将java对象转换成字符串的形式
大多数的java类中的toString()方法都是需要覆盖的,因为Object类中提供的此方法输出的是一java个对象的内存地址。至于怎么覆盖,格式可以自己定义。
多态
父类型的引用指向子类型的对象,即
Animal a2 = new Cat();
a2是父类型的引用,new Cat() 是一个子类型的对象
java中允许向上转型,也允许向下转型,但是两种类型之间必须有继承关系。
向上转型:子类转换成父类(自动类型转换) (upcasting)
Animal a5 = new Cat(); //子类猫转换成父类动物
向下转型:父类转换成子类(强制类型转换,需要加强制类型转换符) (downcasting)
Cat x = (Cat)a5; //父类动物强制转换成子类猫
向下转型有风险吗?
容易出现ClassCastException(类型转换异常)
什么时候使用向下转型?
不要随便做强制类型转换,如果你想使用的方法是子类中特有的方法,就必须进行向下转型
a5.move(); //调用的是子类中的move()方法,这就是多态
什么是多态?
多种形态,多种状态
分析上一条代码的运行原理:
对于编译器来说,编译器只知道a2的类型是Animal,所以编译器在检查语法的时候,会去Animal.class字节码文件中找move()方法,找到了,绑定上move()方法,编译通过,静态绑定成功(编译阶段属于静态绑定)
在运行阶段的时候,实际上在堆内存中创建java对象是Cat对象,所以move的时候,真正参与move的对象是一只猫,所以运行阶段会动态执行Cat对象的move()方法,这个过程属于运行阶段绑定(运行阶段绑定属于动态绑定)
多态指的是:
父类型引用指向子类型对象,包括编译阶段和运行阶段
编译阶段:绑定父类的方法
运行阶段:动态绑定子类对象的方法
当要将鸟类型的变量a1强制转换成猫类型的时,虽然编译器能通过,但运行时会报错,会出现:
java.lang.ClassCastException :类型转换异常
(和 java.lang.NullPointException :空指针异常 一样重要)
怎么避免ClassCastException异常的发生?
instanceof
第一:instanceof 可以在运行阶段动态判断引用指向的对象的类型
第二: instanceof 语法:
引用 instanceof 类型
第三: instanceof 运算符的运行结果只能是: ture/false
假设(c instanceof Cat)为true表示:
c引用指向的堆内存中的java对象是一个Cat
假设(c instanceof Cat)为false表示:
c引用指向的堆内存中的java对象不是一个Cat
任何时候,任何地点,对类型进行向下转型时,一定要使用instanceof 运算符进行判断,这样可以很好的避免:ClassCastException
多态在开发中的作用
非常重要:
面向父类型编程,面向更加抽象进行编程,不建议面向具体编程,因为面向具体编程会让软件的扩展性很差。
软件在扩展过程中,修改的越少越好,修改的越多,系统的稳定性越差,未知的风险就越多
软件开发原则,其中有一条最基本的原则:OCP(开闭原则)
即对扩展开放(可以额外添加),对修改关闭;在软件扩展过程中,修改的越少越好
总结:
降低程序的耦合度,提高程序的扩展力
public class Master{
public void feed(Dog d){}
public void feed(Cat c){}
}
以上代码中,Master和Dog以及Cat的关系很紧密(耦合度高),导致扩展力很差
public class Master{
public void feed(Pet pet){}
}
以上的代码表示,Master和Dog以及Cat的关系就脱离了,Master关注的是Pet类,这样Master和Dog和Cat的耦合度就降低了,提高了软件的扩展性
如果没有多态机制,只有方法覆盖机制,那么方法覆盖可有可无,如果父类方法无法满足子类业务需求的时候,子类完全可以定义一个全新的方法
静态方法存在方法覆盖吗?
方法覆盖和多态不能分开,多态和对象有关系,而静态方法的执行不需要对象,所以一般而言,我们会说静态方法“不存在”方法覆盖,不探讨静态方法的覆盖
私有方法不能覆盖
对于方法覆盖的返回值类型:
对于返回值类型是基本数据类型来说,必须一致;
对于返回值类型引用数据类型,子类中重写之后的返回值类型变小,编译可以通过,但意义不大;反之不行(没有用,一般方法重写都是复制粘贴)