说明:任何类在设计时应考虑覆盖祖先类Object的以下函数:equals,clone,toString等
案例代码:java
public class GeometricObject { //等价于public class GeometricObject extends Object private String color = "white"; private boolean filled; private Date dateCreated; //java.util.Date是JDK定义的类,表示日期和时间 public GeometricObject() { dateCreated = new Date();} //返回当前时间 public String getColor() { return color; } public void setColor(String color) { this.color = color;} public boolean isFilled() { return filled; }//返回Boolean类型 public void setFilled(boolean filled) { this.filled = filled;} public Date getDateCreated() { return dateCreated;} //这里不该该提供setDateCreated方法 @Override //覆盖Object类的toString()方法(返回哈希值) public String toString( ) { //还应考虑equals,clone return "created on " + dateCreated + "\n\tcolor: " + color + " and filled: " + filled; }//toString方法应该返回一个描述当前对象的有意义的字符串 }
子类--------web
public class Circle extends GeometricObject { private double radius; //新增属性 public Circle() { } public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } public void setRadius (double radius) { this.radius = radius; } public double getArea() { return radius * radius * Math.PI; } public double getDiameter() { return 2 * radius; } public double getPerimeter() { return 2 * radius * Math.PI; } //还应考虑equals,clone,toString等函数 } public class Rectangle extends GeometricObject { private double width; private double height; public Rectangle() { } public Rectangle(double width, double height) { this.width = width; this.height = height; } public double getWidth() { return width; } public void setWidth (double width) { this.width = width;} public double getHeight() { return height;} public void setHeight (double height) { this.height = height;} public double getArea() { return width * height;} public double getPerimeter() { return 2 * (width + height); } //还应考虑equals,clone,toString等函数 }
实例初始化模块数组
实例初始化模块最重要的做用是当咱们须要写一个内部匿名类时:匿名类不可能有构造函数,这时能够用实例初始化块来初始化数据成员
安全
public class Book{ private int id = 0; //执行次序:1 public Book(int id){ //执行次序:4 this.id = id } { //实例初始化块 //执行次序:2 } { //实例初始化块 //执行次序:3 } } public class A{ //类的属性和方法定义 { //实例初始化模块 } static { //静态初始化模块 } public static int i = 0;//直接定义静态变量至关于静态初始化块 } public class Book{ private static int id = 0; //执行次序:1 public Book(int id){ this.id = id } static { //静态初始化块 //执行次序:2 } static { //静态初始化块 //执行次序:3 } }
初始化模块执行顺序app
实例:ide
public class InitDemo{ InitDemo(){ new M(); } public static void main(String[] args){ System.out.println("(1) "); new InitDemo(); } { System.out.println("(2) "); } static{ System.out.println("(0) "); } } class N{ N(){ System.out.println("(6) "); } { System.out.println("(5) "); } static { System.out.println("(3) "); } } class M extends N{ M(){ System.out.println("(8) "); } { System.out.println("(7) "); } static { System.out.println("(4) "); } }
class Fruit { public Fruit(String name) { System.out.println("调用Fruit的构造函数"); } } class Apple extends Fruit { } //编译器为Apple提供无参构造函数时出错 //子类Apple没定义任何构造函数,故编译为子类提供无参构造函数Apple(); //提供的Apple()会调用父类无参构造函数Fruit(),因下列缘由没法调用: //父类定义了有参构造函数,因此编译没有为父类提供无参Fruit( )。
子类从新定义了从父类中继承的实例方法,称为方法覆盖
注意事项svg
具体看代码:函数
class A{ public void m() { System.out.println("A's m"); } public static void s() { System.out.println("A's s"); } } class B extends A{ //覆盖父类实例方法 public void m() { System.out.println("B's m"); } //隐藏父类静态方法 public static void s() { System.out.println("B's s"); } } public class OverrideDemo { public static void main(String[] args) { A o = new B(); //父类型变量引用子类对象 o.m(); //因为父类实例方法m被子类覆盖,o运行时指向B类对象,因为多态性,执行的是B的m o.s(); //因为s是静态方法,没有多态性,编译器编译时对象o的声明类型是A,因此执行的是A的s } } // public class OverrideDemo { public static void main(String[] args) { //静态方法隐藏 B o = new B(); o.s(); //调用B的s,将父类A的s隐藏,即经过B类型的引用变量o是不可能调用A的s ((A)o).s(); //经过强制类型转换,能够调用A的s,能够找回。也能够经过类名调用来找回:A.s( ); } //这就是第29页PPT讲的:被隐藏的变量和静态方法能够再发现 }
Circle circle = new Circle(); circle.toString();//Circle@15037e5,若是Circle没有覆盖toString
equals方法测试
public boolean equals(Object o){ if(o instanceof Circle) //应先检查另外一对象o的类型 return radius==((Circle)o).radius;//注意强制类型转换 return false; }
clone方法ui
//首先必须实现Cloneable接口 class A implements Cloneable{ //实现 A能够克隆 public static final int SIZE = 10; private int[] values = new int[SIZE]; //A的values成员是数组 public int[] getValues(){ return values; } //覆盖clone方法,提高为public,只是调用Object的的clone, //不修改行为 @Override public Object clone() throws CloneNotSupportedException { return super.clone();//调用Object的clone } } //Clone方法不带参数,返回Object,同时可能会抛出CloneNotSupportedException异常 public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { A o1 = new A(); A o2 = (A)(o1.clone()); //clone返回Object,所以要强制类型转换 System.out.println(o1 == o2); //false,说明clone返回的是新的引用 System.out.println(o1.getValues() == o2.getValues()); //true 但为浅拷贝克隆 } //由于o1和o2内部values引用指向了内存里同一个数组 //说明A的clone方法里,所调用的super.clone()是浅拷贝 } class A implements Cloneable{ public static final int SIZE = 10; private int[] values = new int[SIZE]; public int[] getValues(){ return values; } public void setValues(int[] newValues) { this.values = newValues; } //覆盖equals方法,比较二个A类型对象内容是否同样 public boolean equals(Object obj) { if(obj instanceof A){ A o = (A)obj; return java.util.Arrays.equals(this.getValues(),o.getValues()); } else return false; } //覆盖clone方法,提高为public,从新实现为深拷贝 public Object clone() throws CloneNotSupportedException { A newObj = new A(); //new一个新对象 newObj.values = this.values.clone(); //数组的clone是深拷贝,若是去掉clone,则是浅拷贝 return newObj; } }
tostring方法
class A implements Cloneable{ //覆盖toString方法 public String toString() { StringBuffer buf = new StringBuffer(); for(int v : values){ buf.append(v + " "); } return buf.toString().trim(); //去掉最后多余的空格 } } public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { A o1 = new A(); o1.setValues(new int[]{ 1,2,3,4,5,6,7,8,9,10}); A o2 = (A)(o1.clone()); System.out.println(o1 == o2); //false System.out.println(o1.getValues() == o2.getValues()); //false 说明不是浅拷贝克隆 System.out.println(o1.equals(o2)); //true,二个对象的内容相等, 说明是深拷贝克隆 System.out.println(o2.toString()); //显示 1 2 3 4 5 6 7 8 9 10 } } // class B implements Cloneable{ A a; //引用类型成员 int i; //值类型 /*若是B类里包含了A类型成员,只要A实现了深拷贝克隆,则B能够很方便地实现深拷贝克隆。如C类里包含了B类型成员,D类型里包含了C类型成员…,以此类推,只要每一个类型都实现了深拷贝克隆,那么最外层的包装类能够很是方便的实现深拷贝克隆。这就是第37页PPT里讲到的克隆的深度问题*/ @Override public Object clone() throws CloneNotSupportedException { B newObj = new B(); newObj.i = this.i; //值类型成员直接=赋值 newObj.a = (A)(this.a.clone()); //引用类型的成员不能直接赋值,必须调用clone方法,深拷贝 return newObj; } }
多态:经过引用变量调用实例函数时,根据所引用的实际对象的类型,执行该类型的相应实例方法,从而表现出不一样的行为称为多态。经过继承时覆盖父类的实例方法实现多态。多态实现的原理:在运行时根据引用变量指向对象的实际类型,从新计算调用方法的入口地址(晚期绑定)。
class Person{ void Greeting( ){ System.out.println(“Best wish from a person!"); } } class Employee extends Person { void Greeting( ){ System.out.println(“Best wish from a employee!");} } class Manager extends Employee{ void Greeting( ){ System.out.println(“Best wish from a manager!");} } public class GreetingTest1{ public static void main(String[] args){ //父类引用变量能够引用本类和子类对象,p1,p2,p3的声明类型都是Person(父类型),p2,p3执行子类对象 Person p1= new Person( ),p2= new Employee( ),p3= new Manager( ); p1.Greeting( ); //调用Person的Greeting() ,因为实际指向对象类型是Person p2.Greeting( ); //调用Employee的Greeting() ,因为实际指向对象类型是Employee p3.Greeting( ); //调用Manager的Greeting() ,因为实际指向对象类型是Manager } }
动态绑定的实现
类型转换
Person p=new Manager();//将子类对象转换为父类对象
Manager m = p; //编译错 ,p是Person父类型,Person不必定是Manager Manager m = (Manager)p;//ok,但转换前没有检查
Manager m = null; if(p instanceof Manager) m= (Manager)p; //安全:转换前检查
instanceof操做符
能够用instanceof操做符判断一个引用指向的对象是不是一个类的实例。表达式返回boolean值。
语法
referenceVariable instanceof TypeName
因此上面的例子安全的写法为:
Person p = new Manager()
if(p instanceof Manager)
Manager m = (Manager)p;
意思是若是p指向的对象真的是Manager实例,再强制转换类型
//警告: 对象访问运算符(.)优先于类型转换运算符。使用括号保证在(.)运算符以前转换 ((Circle)object).getArea() //OK (Circle)object.getArea(); //错误