1.类的成员:
类的成员包括:构造器、类成员变量、实例成员变量、类方法、实例方法、类初始化块、实例初始化块、内部类(接口、抽象类、枚举等)
2.构造器描述:
a.构造器名必须与类名相同,在类的实例化过程中,需要调用构造器,如果类没有构造器,系统会默认提供一个默认的无参构造器。
b.构造器不能定义返回类型(包括void类型),如果构造器存在返回类型,系统会将其当做一个类的方法而不是构造器!
c.构造器可支持重载
d.public修饰构造器,类可以在类内类外实例化;private修饰构造器,类只能在类内实例化(单例模式的实现依赖于这种方式)
单例模式的代码:
public class Test {
public static void main(String arg[]){
Data d = Data.getInstance();
Data d1 = Data.getInstance();
System.out.println(d == d1);
}
}
class Data{
private static Data Instance = null;
private Data(){
System.out.println("Data Init");
}
public static synchronized Data getInstance()
{
if(null == Instance)
{
Instance = new Data();
}
return Instance;
}
}
e.类实例化的过程,会默认将实例成员变量进行初始化,基本类型变量赋值为0/false,引用类型变量赋值为null
3.this对象:
a.this对象表示的是当前对象,即当前运行态执行方法或者获取成员变量的对象,通过这个原则就可以知道当前访问的是那个实例的成员
b.this访问的都是实例成员,是需要实例化后才可以访问的,所以static修饰的静态类方法中是不可以使用this来访问实例成员的
c.通常情况下,访问实例成员的时候有this和没有this是一样的,但是当实例成员和局部变量重名的时候,为了避免歧义就要使用this对象来区分!
d.构造器发生重载的时候,在构造器内部需要调用其他构造器的时候,需要使用this作为构造器名
public class Test{
public static void main(String arg[]){
Data d = new Data("java test");
}
}
class Data{
public Data()
{
System.out.println("Data init");
}
public Data(String name)
{
/*必须放到第一行*/
this();
System.out.println("Data "+name+" init");
}
}
Ps:只有构造器中才可以调用构造器,而且构造器其中调用构造器必须放到函数第一行!
4.可变长行参:
Java1.5 引入形参可变长,格式为:【类型... 变量名】,只能放在参数列表的最后。本质就是数组,但是入参选择数组形式也可以选择可变长行参形式,具体代码如下:
public class Test{
public static void main(String arg[]){
Data d = new Data();
/*可变参数形式*/
d.TestFun(2,3,4,5,6);
/*数组形式,重载的时候只能使用数组的形式*/
d.TestFun(2,new int[]{3,4,5,6});
}
}
class Data{
public void TestFun(int a,int... b){
for(int temp : b)
{
System.out.println(temp);
}
}
}
Ps:当使用可变长形参的时候,如果发生方法重载,必须使用数组形式作为入参,使用多参数的形式不会调到该方法!同样由于可变长形参本质上就是数组,当一个类中同名方法,一个参数为数组,另一个参数为可变长形参,会发生同名方法重复定义的报错!Java的重载为,同类中方法名相同,参数列表不同,与返回值和修饰符无关!
4.类的继承:
a.Java为单继承,但是接口可以用来补充多继承
b.方法重写:
1)子类父类方法名相同,入参相同;
2)子类方法的返回值类型比父类方法的返回值类型小或者相对;
3)子类方法声明抛出异常类比父类方法声明抛出异常类小或者相等;
4)子类方法访问权限比父类方法访问权限大或者相等;
5)子类父类方法同为类方法或者同为实例方法;
Ps:与方法重载比较,方法重载发生在同一个类内,方法名相同,入参不同的时候(返回值类型、方法修饰符不参与判断);方法重写发生在父类子类之间,方法名相同,入参相同的时候;但是如果不满足如上条件2、条件3、条件4、条件5,编译会报错!
c.方法重写的时候,要注意尽可能的避免在父类构造函数中调用被重写的方法,因为当子类构造父类的时候,子类调用父类的构造函数,父类构造函数中调用的是子类重写后的方法(原因是因为当前执行的对象为子类对象,通过打印this对象可以看到),设计不好,容易触发逻辑异常,例如:子类中重写的方法依赖子类构造完成的场景,由于父类构造方法调用的时候,子类还没有构造完成,调用子类重写方法可能发生异常!
public class Test{
public static void main(String arg[]){
DataTemp d = new DataTemp();
}
}
class Data{
public Data(){
System.out.println(this);
test();
}
public void test(){
System.out.println("Data Init");
}
}
class DataTemp extends Data{
public DataTemp(){
System.out.println(this);
test();
}
public void test(){
System.out.println("DataTemp Init");
}
}
输出:
DataTemp@12ac706a
DataTemp Init
DataTemp@12ac706a
DataTemp Init
c.当创建一个子类对象的时候,系统不仅仅会为子类成员分配内存空间,同时也会为其所有父类分配内存空间,并且会从上至下调用构造函数!子类调用父类构造函数的顺序如下:
5.super限定:
a.super限定用来获取父类中的实例方法和实例成员变量,主要应用于方法的重写和子父类中同名成员的覆盖场景!
b.子类构造函数中,调用父类构造函数,使用super();super()也需要放在构造器中的第一行,所以super()和this()不能同时使用!
6.类的多态:
a.当一个引用变量,在编译期类型和运行期类型不一样的时候,就可能发生多态!
b.java引用类型默认都是向上转换的,就是可以将子类赋值给父类;当父类赋值给子类的时候就需要强制类型转换并且保证运行期,父类的内容就是这个子类内容,不然会抛出异常!
c.强制类型转换前,可以使用instanceof运算符来(if (object instanceof TYPE)),判断前一个参数object对象是否是TYPE类或者TYPE子类的实例,进而判断是否可以强制类型转换成功,instanceof前后参数在编译期必须要存在父子类关系,不然会编译报错!
7.初始化块的描述:
a.初始化块就是执行在构造器前面的一段代码块,如果该代码块写在变量初始化前面,代码块会在变量初始化前完成;如果代码块写在变量初始化后面,代码块会改变变量初始化的值,当执行完变量初始化和初始化块后再运行构造器;多个初始化块会按照先后顺序执行;初始化块不存在继承!
b.初始化块的本质:初始化块设计的本质就是将多个构造器中的,参数无关的公共代码统一处理;通过查看class文件可以发现,初始化块在编译后消失了,分别被编译器放到每个构造器中去了!
c.staic修饰静态类初始化块:实例初始化块是在对象创建的时候执行的,类初始化块是在类创建的时候执行的,所以属于类成员;类成员统一满足一个原则,不能访问实例成员,包括实例成员变量、实例方法、super、this对象!