第二章 类
使用继承实现复用,子类对象可以直接赋值给父类变量。
多个重载的构造器里包含相同的初始代码,可以吧这些初始代码放在普通初始化块来完成,初始化块总是在构造器执行之前被调用。
Java还提供静态初始化块
2.1
static修饰的成员叫做类变量、类方法,表示它属于这个类本身,而不属于该类的单个实例,其他没有修饰的则属于某个实例。static修饰的成员不能访问没有static修饰的成员。但是静态变量不仅可以通过类来调用,用实例也可以。
2.2
this
this总是指向调用该方法的对象。this的默认引用有两种方式:1 构造器中引用该构造器正在初始化的对象。2 该方法中引用调用该方法的对象。
this可以代表任何对象,当this出现在某个具体方法中,它代表的对象是不确定的,但它的类型是确定的:它代表的只能是当前类的实例,只有当这个方法被调用时,它所代表的对象才被确定下来。
对于static,可以使用类来直接调用该方法,如果在静态方法中用了this,那this很有可能找不到具体的实例,所以他们两个不能同时用。
你看到的在类中一个方法调用另一个方法,其实被调用的方法默认前面有this,那么当静态方法调用其他非静态,也无法保证非静态有对应的对象,如果一定要在静态里面调用非静态,就给非静态new一个实例然后调用。113页
2.3
Java中 只有 值传递。 就是传入实际参数的副本。当然了,引用类型一个引用传进去,也是可以达到修改原参数的效果。
方法的形参可以变长,
test (int a, string … arr)
这样既可以在最后传入n个string,也可以传入string数组。但可变参数只能有一个而且放最后。
2.4成员变量和局部变量
变量可以分为两类:成员变量和局部变量。
成员变量是类里定义的变量,又分成类变量和实例变量。
类变量的生命和类相同,实例变量的生命和对象一样,这两种变量都属于成员变量。
🤔类初始化的时候,会给类分配内存空间,而这个类变量和类的初始化是一起的。当new了一个对象后,在堆中给对象分配内存,在栈中分配引用,指向堆中的实例,这个实例对象的地址和类是不一样的。
局部变量分为三种:形参,方法局部变量,代码块局部变量。
局部变量除了形式参数,都必须初始化,否则不能访问,因为系统不会为局部变量执行初始化,直到程序为他赋值,系统才会给他分配内存。局部变量与成员变量同名会覆盖成员变量,如果需要在这个方法里引用被覆盖的成员变量,可以用this。
2.5成员变量的初始化和内存中的运行机制
当系统加载类或者创建实例的时候,自动为成员变量分配内存,自动为他们指定初始值。
String的成员变量也是引用,指向给的字符串。
2.6局部变量的初始化和内存中的运行机制
Java中类型可以分为两大类:值类型和引用类型。
值类型就是基本数据类型,如int,double,而引用类型就是指除了基本的变量类型之外的所有类型。
声明一个值类型变量,编译器会在栈上分配一个空间,这个空间存储的就是该变量的值。
引用类型的实例分配在堆上,新建一个引用类型实例,得到的变量值对应的是该实例的内存分配地址,
装箱,其实就是值类型到引用类型的转化过程,将一个值类型变量装箱成一个引用类型。还有拆箱。
例子:
Int age =new int();
object ageObject =age; 这就是一个装箱,ageObject装的是存age的地址
//ageObject=null;
age =(int)ageObject. 这就是一个拆箱
要注意的一个地方就是,如果去掉注视,这个程序就会报错,这是因为,把一个空的引用,要取值赋给age,这从哪取值,取不到的,而值类型不一样了,他不可能是空,你不服值,就默认是0了。
引用类型变量的Equals比较的引用地址,不是内部的值,值类型不能作为任何类的基类型,因此不能向值类型中增加任何新的虚方法,更不该有任何抽象方法,所有方法都不可重写。值类型在栈上,一旦值类型变量范围一过,就像没有存在过一样。
引用类型是你能够定义自己的数据类型来抽象任意对象。
抽象数据类型ADT=(D,S,P)D是数据对象,S是D上的关系集,P是D的基本操作集。
super:super可以调用从父类那里继承来的实例变量和方法,所以super是不能出现在static中的,如果被覆盖的是类变量,就直接可以用方法名来访问。
在创建一个子类对象的时候,不仅会为改类中的实例变量分配内存,也会对从他的直接父类和间接父类继承过来的实例变量一起分配内存,即使子类中定义了和父类同名的变量。
当new了一个子类的对象,想要访问父类的方法,可以显式的向上转型,例145页。
创建任何类对象总是从该类所在继承树的最顶端类的构造器开始执行,最后才执行本类的构造器。
多态
就是声明父类对象去new一个子类,这样的话,在编译的时候,对象是父类的类型,但是在运行的时候就是子类的类型,执行的是子类的方法,但是执行成员变量的时候,则是父类的。
就是,当子类继承父类的时候,所有父类的变量也会继承过来,即便子类里面有同名的变量,也不会覆盖,只是会隐藏,如果声明父类,new子类,访问的是父类变量。也就是说,实例变量是在静态绑定。
当然你要是强转成子类了,那当然是子类的了,你都强转了,你和声明子类new子类有什么区别?
而且,如果调用的某些方法子类没有重写,那还是执行原本父类的方法。从写代码的角度看,只能调用原有父类的方法。但是!!执行的时候,是new子类啊,所以那些只属于子类的方法要怎么办呢,就要强制类型转换。
子类一定是可以继承父类所有的,请你记得,如果子类方法没有覆盖父类,new子类就直接调用父类,不然你没重写的那些toString,equals,如果不能用,那从哪来的???!!!
关于继承和组合:
继承是一种is a的关系,比如狼和动物的关系,组合是一种has a的关系,什么是组合,其实也就是把一个类当作另一个类的成员变量,(就看成一个普通成员变量就行),然后在类方法里调用那个类的函数。
要想一个类不被任何类继承,用final修饰。或者用peivate修饰这个类的构造器。
instanceof 运算符
前面写一个引用类型的变量,后面通常是一个类,或者是一个接口,前面的变量要么是与后面的类相同,要么是有父子继承关系,否则会编译错误。在151的例子里面,虽然声明了Object,但是 Object s=“hello”,s实际上还是String类型。
什么时候返回true什么时候返回false呢,也就是要不然是同一个类,要不然后面是一个接口,前面的类实现了后面类的接口。
构造方法:
如果一个类没有写任何构造方法,系统会默认给他一个无参数的,子类在构造方法当中,必须加上父类的构造方法,但是,如果两个都不写,那么系统都给了两个默认的,那也可以。
构造器
类至少包括一个构造器,不写就给你默认一个。默认初始化是0或者false,引用类型是null。
Q:🤔构造器完全负责创建Java对象吗?
Answer:new调用构造器。实际上,在调用构造器时系统就先为对象分配了内存空间,并为对象执行了默认初始化,对象就产生了,但这个对象还不能被访问只能在构造器中用this访问。
一旦写了一个构造器,系统就不再提供不带参的了。
构造器重载的时候,如果有完全包含其他构造器代码的可以调用,this( , ),但是this调用别的构造器只能是构造器的第一行。
网友评论