一、构造器与初始化块
1、构造器是一个特殊的方法,其方法名与类名相同,且没有返回值,并且通过new关键字调用。
2、它是创建对象的重要途径(即使使用反射),主要负责执行一些自定义的的初始化,虽然初始化块也有此功能但不怎么常用。
3、构造器也可以重载,在一个构造器里可以通过this关键字和相应参数列表调用另一构造器。
4、如果没有为类提供自定义的构造器,则系统会为这个类提供一个默认无参的构造器,一旦我们自定义了构造器, 则默认无参构造器便不再有,通常建议自定义构造器时要额外编写一个无参构造器。通过new关键字及相应参数列表就可以 调用类对应的构造器进行初始化。
5、创建实例时,构造器的存在一个不断上溯的隐含调用,直到根(Object)构造器为止。初始化块作为对构造器的一种补充也有这一特点,只是静态初始化块只会在类加载时调用一次且优先于分静态初始化块和构造器,而分静态初始块优先于构造 器,与属性声明时初始化语句具有同等执行优先级,例如如下程序:
class A
{
public A(){
System.out.println("A----------------构造器!");
}
{
System.out.println("A----------------非静态代码块!");
}
static{
System.out.println("A----------------静态代码块!");
}
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
public class B extends A
{
public B(){
System.out.println("B----------------构造器!");
}
{
System.out.println("B----------------非静态代码块!");
}
static{
System.out.println("B----------------静态代码块!");
}
public static void main(String[] args)
{
B a = new B();
}
}
其执行结果为:
二、封装
1、封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对这些内部状 态的操作与访问。由此可见封装实际上涉及到两个方面,隐藏该隐藏的(状态),暴露该暴露的(方法)。
2、对一个类或对象实现良好的封装,可以实现以下目标:
1、隐藏类的实现细节。
2、让使用者只能使用事先预定的方法来访问数据,从而可以在方法里加入控制逻辑,限制对属性的不合理访问。
3、可进行数据检查,从而有利于保证对象信息的完整性。
4、便于修改,提高代码的可维护性。
三、继承
1、继承是实现软件复用的重要手段,而继承关键字extends则说明了另一个方面,那就是子类对父类的功能扩展。
2、java不支持多继承。
3、子类可以重写父类方法,但要遵循两“两同两小一大”规则:
(1)、“两同”即方法名相同、参数列表相同。
(2)、"两小"即子类方法返回值类型应该小于等于子类方法返回值类型,子类方法声明抛出的异常类应该比父类方法声明抛出的异常类更小或相等,"一大"即子类方法的访问权限应该比父类更大或者相等。
(3)、“一大”指的是子类方法的访问权限应该大于等于父类方法,且覆盖方法与被覆盖方法必须同为类方法或者同为实例方法。如果父类方法为private访问权限,则该方法对其子类是隐藏的,若子类中有一与此private方法签名相同的方法也不认为是覆盖,而只是子类的一个新方法而已。
4、如果子类定义了与父类同名的属性,也会发生覆盖的情形,而且子类里定义的方法也只能访问到覆盖属性,父类属性也可以通过super来点取。
5、继承注意点:
(1)、当创建子类实例时,在为子类对象分配堆内存时也会为父类被覆盖的属性分配空间,即会有两个同名属性同时存在于此堆中。
(2)、尽量隐藏父类的内部数据,不要让子类可以随意访问、修改父类方法。
(3)、不要在父类构造器中调用被子类重写的方法,这一点一定要注意,看下面程序:
class D
{
private String d;
public D(){
this.d = prn(); //调用getD()方法
}
public String prn(){
System.out.println("d");
return "d";
}
public String toString(){
return d;
}
}
public class E extends D
{
public String prn(){ //重写父类中getD()方法
System.out.println("e");
return "e";
}
public static void main(String[] args)
{
System.out.println(new E());
}
}
其执行结果为:
可见父类构造器调用被子类重写的方法进行初始化时对父类中方法所执行的初始化操作会视若无睹,有一定安全隐患!
四、多态
1、java引用变量有两个类型,编译时类型与运行时类型。编译时类型由声明该变量时使用的类型决定,运行时的类型由实 际赋给该变量的对象决定。编译时类型与运行时类型活动的不一致就是多态。
2、多态有两个注意点:方法与属性。通过下面的程序来进行直观的分析。
class A {
public String a="A";
public void method1(){
System.out.println("A1");
}
}
class B extends A{
public String a="B";
public void method1(){
System.out.println("B1");
}
public void method2(){
System.out.println("B2");
}
}
参照上面的程序,有如下分析:
(1)、向上转型: A a = new B(); 把子类对象赋给了父类类型变量,这个转型时系统自动进行的,并且总是安全的
向下转型: B b = a; 把父类类型变量赋给子类类型变量,这个属于强制转型,并且有一定风险为了确保安全,一般使用如下形式进行向下转型
if(a instance B){
B bb = (B)a;
}
上面的两种转型体现的就是多态。
(2)、在多态中有两个注意点:
1.方法:看运行时类型,即new的谁就执行谁的方法, 可执行的方法要看编译时类型,即编译的类里面有什么方法该变量才可以运行什么方法像上边a变量就只能调用method1()方法且打印结果为“B1”。
2.属性:只看编译时类型,向上边用变量a访问实例变量a时,值就为"B"。