Java日志第10天 2020.7.15

第五章 类的继承和多态

5.1 Java中的继承

子类继承父类的属性和方法,并根据需要增加它为自己的新的属性和方法。由此而得到的类为子类,被继承的类为父类,也叫超类。Java不支持多继承(子类只能有一个父类)。

*5.1.1 Object类及其方法

Java中的所有类都默认继承Object类,Object是Java所有类的父类。

定义:public class Object

*5.1.2 对象中的克隆

Java克隆是Java语言的特性之一,在实际中应用比较少见。但有时用方法会更方便、更有效率

(1)克隆的限制

  *被克隆的类必须自己实现Cloneable接口,以指示Object.clone()方法可以合法的对该类实例进行按字段赋值。Cloneable接口实际上是个标识接口,没有任何接口方法。

  *实现Cloneable接口的类应该使用公共方法重写Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。

  *在Java.lang.Object类中克隆方法是这么定义的。

  protected Object clone()

  throws CloneNotSupportedException

(2)浅层克隆和深层克隆

  *浅层克隆:主要复制基本对象的值

  *深层克隆:当类存在聚合关系是,克隆就必须考虑聚合对象的克隆。可以复制引用类型的字段。

示例:浅层克隆

public class CloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person("任我行", 35);
Person p2 = (Person)p.clone();
System.out.println("克隆前:"+p.getName()+","+p.getAge());
System.out.println("克隆后:"+p2.getName()+","+p2.getAge());
if(p == p2){
System.out.println("p和p2的地址相等!");
} else{
System.out.println("p和p2的地址不相等!!");
}

}
}
/*简单类克隆实现
要实现克隆,必须实现Cloneable接口,这是一个标识接口,没哟接口方法
实现了Cloneable接口,以指示Object.clone()方法
可以合法地对该类实例进行按字段复制
按照惯例,实现此接口的类应该使用公共方法重写Object.clone(它是受保护的)
*/
class Person implements Cloneable{
private String name;
private int age;
public Person(String name, int age){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
@Override
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}

示例:深层克隆

public class CloneDeepDemo {
public static void main(String[] args) throws CloneNotSupportedException{
Person per = new Person("令狐冲",20);
P p = new P(per);
P p2 =(P)p.clone();
System.out.println("克隆前:"+p.getPer().getName()+","+p.getPer().getAge());
System.out.println("克隆后:"+p2.getPer().getName()+","+p2.getPer().getAge());
if(p==p2)
System.out.println("p和p2的地址相等!");
else
System.out.println("p和p2的地址不相等!");
if(p.getPer()==p2.getPer())
System.out.println("p中的Person对象与p2中的Person对象相等!");
else
System.out.println("p中的Person对象与p2中的Person对象不相等!");
}
}
class P implements Cloneable{
Person per;
public P(Person per){
this.per = per;
}
public Person getPer(){
return per;
}
public void setPer(Person per){
this.per = per;
}
@Override
protected Object clone() throws CloneNotSupportedException{
P p = (P)super.clone();
p.per = (Person)this.per.clone();
return p;
}
}

 5.1.3 Java的继承

Java中的继承使用关键字“extends”表示,

公式:class 子类 extennds 父类 {}

使用继承子类可以拥有父类中的非私有属性

示例:

定义一个Person类

public class Person {
public String name;
public String sex;
public int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getSex(){
return sex;
}
public void setSex(String sex){
this.sex=sex;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}

}

定义Student类继承Person类
public class Student extends Person {
private String deparetment;//系别
private String specialty;//专业
}

public class day06 {
public static void main(String[] args) {
Student s = new Student();
//子类共享父类中的非私有属性
String str=s.name;
//子类可以拥有父类中的非私有方法
s.setName("伍正云");
s.setAge(25);
}
}

*Java不支持不支持多继承,一个类只能继承一个类,即子类只能继承一个父类,但是一个父类可以被多个子类继承。

5.1.4 super关键字
在Java继承中,子类可以使用super富案件自调用父类的非私有属性和非私有方法,还可以调用父类的非私有构造方法。
(1)使用super关键字调用父类属性
public class Person {
public String name;
public String sex;
public int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getSex(){
return sex;
}
public void setSex(String sex){
this.sex=sex;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}

}

public class Student extends Person {
private String deparetment;//系别
private String specialty;//专业
String name1 = super.name; //调用父类的属性name
public void test(){
super.getAge(); //调用父类方法
}
}

*super关键字可以省略
public class Student extends Person {
private String deparetment;//系别
private String specialty;//专业
String name1 = name; //调用父类的属性name
public void test(){
getAge(); //调用父类方法
}
}

(2)使用super调用父类的构造方法
public class Person {
private String name;
private int age;
public Person(){

}
public Person(String name, int age){
this.name = name;
this.age = age;
}
}
class Student extends Person{
public Student(){
super("sky",26);
}
}

(3)子类和父类构造方法的执行顺序
*子类默认调用父类的无参构造方法,也就是说,子类的构造方法中会默认调用super(),并且在构造方法的第一行。
*如果子类只提供有参的构造方法,则必须在子类的构造刚发中调用父类的构造方法。
*执行父类的构造方法后,在调用本类中的构造方法。
public class Person {
private String name;
private int age;
public Person(){
System.out.println("父类无参构造方法");
}
public Person(String name, int age){
this.name = name;
this.age = age;
System.out.println("父类有参构造方法");
}
public static void main(String[] args){
Student stu = new Student();
}
}
class Student extends Person{
public Student(){
super("sky",26);
System.out.println("子类有参构造方法");
}
}

5.2 多态变化

5.2.1 Java中多态的实现

覆盖:子类重写父类中的方法

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
Son son = new Son();
son.say();
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
}

5.2.2 类型检测——向上转型/向下转型

向上转型是指父类对象的引用指向子类对象。向下转型是指在向上转型的基础上再次指向子类对象。

(1)向上转型

语法:父类 对象 = new 子类()

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
//向上转型
Father son = new Son();
son.say();
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
}

 有时使用向上转型会丢失掉子类特有的方法

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
//向上转型
Father son = new Son();
son.sayMe();//报错
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
public void sayMe(){
System.out.println("Son sayMe()");
}
}
 
(2)向下转型
语法: 父类 对象1 = new 子类()
    子类 对象2 = (子类)对象1

public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
//向上转型
Father son = new Son();
//向下转型
Son son2 = (Son)son;
son2.sayMe();//报错
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
public void sayMe(){
System.out.println("Son sayMe()");
}
}

如果直接将父类强转成子类对象会报错
public class Father {
public void say(){
System.out.println("Father say()");
}

public static void main(String[] args) {
Father f = new Father();
Son son = (Son)f;
}
}
class Son extends Father{
public void say(){
System.out.println("Son say()");
}
public void sayMe(){
System.out.println("Son sayMe()");
}
}

5.2.3 动态绑定
*动态绑定
会基于对象实际的类型(只能在运行时得知)来选择所调用的方法
*静态绑定
在程序编译时就绑定的,在Java中的变量都是静态绑定的,只有private、static和final是静态绑定的。
原文地址:https://www.cnblogs.com/Gazikel/p/13304854.html