1 对象转型
- 一个基类的引用类型变量可以“指向”其子类的对象。
- 一个基类的引用不可以访问其子类对象新增加的成员(属性和方法)。
- 可以使用引用变量instance of 类名 来判断该引用型变量所“指向”的对象是否属于该类或该类的子类。
- 子类的对象可以当做基类的对象来使用称作向上转型(upcasting),反之成为向下转型(downcasting)。
例子1:
class Animal{
public String name;
Animal (String name){
this.name = name;
}
}
class Cat extends Animal {
public String eyesColor;
Cat(String n,String c){
super(n);
eyesColor = c;
}
}
class Dog extends Animal{
public String furColor;
Dog(String n,String c){
super(n);
furColor = c;
}
}
public class TestDuo{
public static void main(String[] args){
Animal a = new Animal ("name");
Cat c = new Cat("catname","blue");
Dog d = new Dog("dogname","black");
System.out.println(a instanceof Animal);//true
System.out.println(c instanceof Animal);//true
System.out.println(d instanceof Animal);//true
System.out.println(a instanceof Cat);//false
//只能访问基类中的属性和方法,“yellow”无效会报错
a = new Dog("bigyellow","yellow");
System.out.println(a.name);//bigyellow
System.out.println(a.furColor);//!error
System.out.println(a instanceof Animal);//true
//instanceof会检测a的实际类型
System.out.println(a instanceof Dog);//true
Dog d1 = (Dog) a;//要加强制转换符
System.out.println(d1.furColor);//yellow
}
}
2 动态绑定和多态(提高可扩展性)
动态绑定是指在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
class Animal{
private String name;
Animal(String name){
this.name = name;
}
public void enjoy(){
System.out.println("叫声。。。");
}
}
class Cat extends Animal{
private String eyeColor;
Cat(String n,String c){
super(n);
eyesColor = c;
}
public void enjoy(){
System.out.println("miaomiao");
}
}
class Dog extends Animal{
private String furcolor;
Dog(String n,String c){
super(n);
furcolor = c;
}
public void enjoy(){
System.out.println("wangwang");
}
}
class Lady{
private String name;
private Animal pet;
Lady (String name, Animal pet){
this.name = name;
this.pet = pet;
}
public void myPetEnjoy(){
pet.enjoy();
}
}
public class Test{
public static void main(String[] args){
Cat c = new Cat("catname","blue");
Dog d = new Dog("dogname","black");
Lady l1 = new Lady("11",c);
Lady l2 = new Lady("12",d);
l1.myPetEnjoy();//miaomiao
l2.myPetEnjoy();//wangwang
}
}
上面的例子中,根据Lady对象的成员变量pet所引用的不同的实际类型而调用相应的enjoy方法。
动态绑定的三个条件:1. 要有继承 2.要有重写 3.父类引用指向子类对象
3 抽象类(只需要定义不需要实现的基类可以使用抽象类定义)
- 用abstract关键字来修饰一个类时,这个类叫做抽象类;用abstract来修饰一个方法时,该方法叫做抽象方法。
- 含有抽象方法的类必须被声明为抽象类,抽象类必须被继承,抽象方法必须被重写(除非子类也是抽象类,则可以不重写)。
- 抽象类不能被实例化。
抽象方法只需声明,而不需实现。
上例中的基类Animal可以写成如下抽象类:
abstract class Animal{
private String name;
Animal(String name){
this.name = name;
}
public abstract void enjoy();//必须被重写
}
4 final关键字
- final的变量的值不能够被改变(final的成员变量和final的局部变量(形参))
- final的方法不能够被重写
- final的类不能够被继承 (String类)
5 接口
- 多个无关的类可以实现同一个接口;一个类可以实现多个无关的接口;与继承关系类似,接口与实现类之间存在多态性。接口之间可以继承,类只能实现接口。
- 接口是抽象方法和常量值的定义的集合,从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
接口的特性:
- 接口可以多重实现
- 接口中声明的属性默认为public static final的,也只能是public static final的
- 接口中只能定义抽象方法,而且默认为public的,也只能是public的
- 接口可以继承其他的接口,并添加新的属性和抽象方法。
接口定义如下:
interface Singer{
public void sing();
public void sleep();
}
interface Painter{
public void paint();
public void eat();
}
class Student implements Singer{
private String name;
Student(String name){
this.name = name;
}
public void study(){
System.out.println("studying");
}
public String getName(){
return name;
}
public void sing(){
System.out.println("student is singing");
}
public void sleep(){
System.out.println("student is sleeping");
}
}
//
class Teacher implements Singer,Painter{
private String name;
public String getString(){
return name;
}
Teacher(String name){
this.name = name;
}
public void teach(){
System.out.println("teaching");
}
public void sing(){
System.out.println("teacher is singing");
}
public void sleep(){
System.out.println("teacher is sleeping");
}
public void paint(){
System.out.println("teacher is painting");
}
public void eat(){
System.out.println("teacher is eating");
}
}
public class TestFinal{
public static void main(String[] args){
Singer s1 = new Student("le");//只能看到Singer的方法
s1.sing(); s1.sleep();
Singer s2 = new Teacher("steven");
s2.sing(); s2.sleep();
Painter p1 = (Painter) s2;//只能看到Painter的方法
p1.paint(); p1.eat();
}
}
运行结果: