11.15
类的继承
一、继承的特点
1.子类会自动继承父类所有的属性和方法
class B extends A
B继承A,B为子类,A为父类
2.子类不会继承父类的私有成员
3.Java只支持单继承,不支持多继承(一个子类只能有一个父类),但是可以多重继承(一个父类可以有多个子类)
二、子类和父类之间的类型转换
1.将子类当父类来用可以(有限制),将父类当子类来用不行
2.
eg:
class B extends A
A a = new B();
把一个子类当做父类来用的时候,父类类型的变量中存放的地址是指向一个子类的实例对象的,所以理论上是可以调用子类中定义的任何方法的实验证明,如果用一个父类类型的变量是指向子类对象时,用该变量去调用子类中自定义的方法时,编译器会报错,原因就在于,Java编译器会检查语法,看到父类类型的变量调用方法时,就会检查父类中是否定义了这样的方法,这种情况下,就需要强制类型转换,将父类类型强转成子类类型,前提是父类变量指向的子类对象,可以使用instanceof进行判断
if(a intanceof B)
{
B b = (B)a;//将父类类型强转成子类类型
...
}
3.父类变量引用子类对象时,调方法(重写方法)调的是子类的(动态绑定),访问变量时访问父类的(静态绑定)
注意:此处的方法是父类和子类中都有的方法,即子类重写父类的成员方法
eg:
class A
{
String name = "A";
public void run()
{
System.out.println("你好坏!!!");
}
}
class B extends A
{
String name = "B";
public void run()
{
System.out.println("你真好!!!");
}
}
class Demo
{
public static void main(String [] args)
{
A a = new B();//父类变量引用子类对象
System.out.print(a.name+" ");//静态绑定
a.run();//动态绑定
}
}
运行结果:A 你真好!!!
三、子类实例化
先来看一个问题
构造方法不会被继承,但会被调用
当子类继承父类时,同时也会继承父类所有的属性和方法,但要想调用父类的属性和方法,必须要有对象,要初始化对象,就涉及到构造方法了。所以,当我们初始化子类对象时,必然会调用父类的构造方法,至于是调用哪个构造方法,看下面...
a.子类在实例化过程中一定会有一个父类的构造方法被调用
b.如果在子类的构造方法中没有显式地声明去调用父类哪个构造方法的时候,系统会自动去调一下父类无参的构造方法。
即:子类构造方法的第一行隐藏了一句代码:super();无参构造才会隐藏
c.在子类中第一行用this关键字去调用子类其他的构造方法,这时系统将不再自动调父类的无参构造方法
d.在同一个构造方法中this和super关键字只能出现一次,而且必须是第一行
e.在设计类的时候,一定要定义一个无参的构造方法,不然子类实例化的时候就会容易出错
了解下这种机制
我们在设计一个类的时候,需要该类的对象都具有某一项特殊的功能,就需要在构造方法里做一些特殊的事情,别人来继承我们这个类,一定也希望子类对象也具备这样的功能,但是别人并不知道在构造方法中需要做一些特殊的事情才能实现这样的功能,所以java就规定子类实例化过程中,一定会去调用父类的其中一个构造方法,这样就能保证子类对象具有和父类对象相同的特殊功能
四、重写方法(方法的覆盖)
这里所说的方法是指成员方法的覆盖,提醒一下
1.覆盖方法时,不能使用比父类中被覆盖的方法更严格的访问权限
即:父类方法如果是private,子类是public,那就错了
2.如果在子类中想调用父类中的那个被覆盖的方法,我们可以用super.方法名()的格式
3.返回值类型、方法名和参数列表必须和父类的一样
补充:什么情况下用super关键字
父类Person中有shopping方法,定义的子类Chinese中也有shopping方法,但跟父类的有所区别,这样我们就可以先把子类shopping方法中的某些个性先写出来,然后在调用父类的shopping方法
即...super.shopping();
五、final关键字
这个比this和super简单,比较好理解,记住几点就行了
1.用final来修饰的类是终态类,不能被继承
2.用final来修饰的方法,可以被子类继承,但不能被子类重写(覆盖)
3.final修饰的变量值不能改变,为常量 用public static final来修饰一个常量
4.final修饰的形参,对于方法体来说是常量,在方法体中值不能改变
六、组合设计模式
先看代码:
class Card
{
public void sppend()
{
System.out.println("花了一分钱...");
}
}
class Person
{
private Card card;
public Person(Card card)
{
this.card = card;
}
public void shopping()
{
card.sppend();
}
}
class Demo
{
public static void main(String [] args)
{
Card card = new Card();
Person per = new Person(card);
per.shopping();
}
}
有的时候,我们用到的类(Card)和当前类(Person)没有明显的父子关系,我们在定义一个类(Person)的时候需要用到另外一个类(Card)的方法时,就可以用组合,
将用到的类定义为当前类的一个属性,通过构造函数进行装配
在编程过程中要尽量多使用组合,少使用继承,因为Java只支持单继承,用组合就不占用继承的那个名额了
我们也可以在组合设计中穿插继承效果,改变一下上面的代码,同时也运用下关键字super
class Card
{
public void sppend()
{
System.out.println("花了一分钱...");
}
}
class Person
{
private Card card;
public Person(Card card)
{
this.card = card;
}
public void shopping()
{
card.sppend();
}
}
class Chinese
{
private Card card;
public Chinese(Card card)
{
super(card);
}
public void shopping()
{
System.out.println("能便宜点吗?");
super.shopping();//调用父类的方法
}
}
class Demo
{
public static void main(String [] args)
{
Card card = new Card();
Chinese ch = new Chinese(card);
per.shopping();
}
}