继承(extends)
-
什么是继承?继承有什么用?
继承:在现实世界中也存在,例如:父亲有钱,儿子不用努力也很有钱
继承的作用:
-
基本作用:子类继承父类,代码可以得到复用。
-
主要/重要作用:有了继承关系,才有了后期的方法覆盖和多态机制
-
-
继承的相关特性
-
B类继承A类:A类为超类(superclass)、父类、基类。
B类则称为子类(subclass)、派生类、扩展类
class A{} class B extends A{} //我们平时聊天说的比较多的是:父类和子类。 suoperclass 父类 subclass 子类
-
java中的继承只支持单继承,不支持多继承 ,C++中支持多继承
这也是java体现简单性的一点,换句话说,java中不允许这样写代码:
class B extends A,C{}//这样写是错误的.
-
虽然java不支持多继承,但有的时候会产生间接继承的效果,例如:
calss C extends B{} class B extends A{} //也就是说:c直接继承B、其实C还间接继承A.
public class ExtendsTest02 {public static void main(String[] args){}} class AA{} class BB{} class CC extends AA{} class DD extends BB{} //语法错误 //java只允许单继承,不允许多继承。java是简单的,C++支持多继承。 //C++更接近现实一些。现实中:儿子同时继承父母亲的基因。 //class EE extends AA,BB{} class XX{} class YY extends XX{} //其实这样也说明了ZZ是继承XX和YY的。 //详细描述:ZZ直接继承了YY ,间接继承了XX。 class ZZ extends YY{}
-
java中规定:子类继承父类,除了构造方法不能继承外,剩下的都可以继承,但是私有的属性无法在子类中直接访问。(父类中private修饰的不能在子类中直接访问,可以通过间接的手段访问,如:使用set和get方法)
-
java的类没有显示的继承任何类,则默认继承Object类,Object类是java语言提供的根类(老祖宗类),也就是说:类一旦创建,就有Object类型中所有的特征。
//C继承B,B继承A,A继承Object //C具有所有的Object对象的特征(基因) //Object是所有类的超类、老祖宗,是类体系结构中的根。 //java这么庞大的一个继承结构,最顶点:Object
-
继承也有缺点: 如:CreditAccount类继承Account类会导致它们之间的耦合度非常高,Account类发生改变之后马上影响到CreditAccount类。
/* 使用继承解决 继承:除了构造方法其他的都继承,私有化的属性也继承,但是在子类中不能直接访问 继承也是有缺点的:耦合度高,父类修改,字类受牵连。 */ public class ExtendsTest01 { public static void main(String[] args){ //创建普通账户 Account1 act = new Account1(); act.setActNo("123456"); act.setBalance(10000); System.out.println(act.getActNo()+"的余额:"+act.getBalance()); //创建信用账户 CreditAccount ca = new CreditAccount(); ca .setActNo("654321"); ca.setBalance(-20000); ca.setCredit(0.99); System.out.println(ca.getActNo()+"的余额:"+ca.getBalance()+" \t他的信誉为:"+ca.getCredit()); } } //银行账户类 //账户属性:账户、余额 class Account1{//父类 //属性 private String actNo; private double balance; //构造方法 public Account1(){} public Account1(String actNo,double balance){ this.actNo = actNo; this.balance = balance; } //set 和 get 方法 public String getActNo(){ return actNo; } public void setActNo(String actNo){ this.actNo = actNo; } public double getBalance(){ return balance; } public void setBalance(double balance){ this.balance = balance; } } //其他类型的账户:信用卡账户 //账号、余额、信誉度 class CreditAccount extends Account1{//子类 private double credit; //构造方法 public CreditAccount(){} public void doSome(){ //错误: actNo 在 Account1 中是 private 访问控制 //继承的私有属性无法直接访问。 //System.out.println(actNo); //只能间接访问 System.out.println(getActNo()); } //set 和 get 方法 public double getCredit(){ return credit; } public void setCredit(double credit){ this.credit = credit; } } /*分析以下程序存在什么问题? 代码臃肿,代码没有得到复用性。 */ /* public class ExtendsTest01 { public static void main(String[] args){ //创建普通账户 Account1 act = new Account1(); act.setActNo("123456"); act.setBalance(10000); System.out.println(act.getActNo()+"的余额:"+act.getBalance()); //创建信用账户 CreditAccount ca = new CreditAccount(); ca .setActNo("654321"); ca.setBalance(-20000); ca.setCredit(0.99); System.out.println(ca.getActNo()+"的余额:"+ca.getBalance()+" \t他的信誉为:"+ca.getCredit()); } } //银行账户类 //账户属性:账户、余额 class Account1{ //属性 private String actNo; private double balance; //构造方法 public Account1(){} public Account1(String actNo,double balance){ this.actNo = actNo; this.balance = balance; } //set 和 get 方法 public String getActNo(){ return actNo; } public void setActNo(String actNo){ this.actNo = actNo; } public double getBalance(){ return balance; } public void setBalance(double balance){ this.balance = balance; } } //其他类型的账户:信用卡账户 //账号、余额、信誉度 class CreditAccount{ private String actNo; private double balance; private double credit; //构造方法 public CreditAccount(){} public CreditAccount(String actNo,double balance,double credit){ this.actNo = actNo; this.balance = balance; this.credit = credit; } //set 和 get 方法 public String getActNo(){ return actNo; } public void setActNo(String actNo){ this.actNo = actNo; } public double getBalance(){ return balance; } public void setBalance(double balance){ this.balance = balance; } public double getCredit(){ return credit; } public void setCredit(double credit){ this.credit = credit; } } */
-
-
测试: 字类继承父类之后,能使用字类调用父类方法吗?
/* 测试: 子类继承父类之后,能使用子类调用父类方法吗? 本质上,子类继承父类之后,父类继承过来的方法归自己所有。 继承:把父类的东西复制一份挪过来。 实际上调用的也不是父类的方法,是子类自己的方法(因为已经继承过来了,就属于自己的。) */ public class ExtendsTest03 { public static void main(String[] args){ Cat c = new Cat(); //调用父类中方法 c.move(); //子类可以访问name吗 //父类属性如果没有封装,子类可以访问。封装后使用get以及set方法读改。 System.out.println(c.name);//可以 } } class Animal{//先不封装 //名字 String name = "xiaohua"; //提供一个动物移动的方法 public void move(){ System.out.println(name +"正在疾跑"); } } //Cat类继承Animal类,会将Animal中除构造方法外的东西都继承过来。 class Cat extends Animal{ }
-
在实际开发中,满足什么条件时才可以使用继承?
/* 凡是采用“is a” 能描述的,都可以继承。 例如:Cat is a Animal :猫是一个动物 例如:Dog is a Animal :狗是一个动物 CreditAccount is a Account :信用卡是一个银行账户 ...... 假设以后开发中有一个A类,有一个B类,A类和B类确实也有重复的代码,那么他们两个之间就可以继承吗? 不一定,还是要看他们之间是不是可以使用is a来描述 */ class Customer{ String name;//名字 //set以及get 方法 } class Product{ String name //名字 //set以及get 方法 } //class Product extends Customer{} //这种继承就是错误的,因为Product is a Customer 是不符现实的。 //虽然他们都有名字这个属性,但一个是人,一个是东西。所以继承主要还是要两个类之间存在关系。
-
任何一个类,没有显示继承任何类,默认继承Object,那么Object类当中有哪些方法呢?老祖宗为我们提供了哪些方法?
println()方法的解释
/* out后面没有小括号,说明out是变量名。System是一个类名,类名.out,说明out是一个静态变量。 System.out返回一个对象,然后采用“对象.”的方式访问println()方法。 */ //以下代码中:System out println都是标识符 public class Test3 { //静态变量 static Student6 stu = new Student6(); //入口 public static void main(String[] args){ //拆分为两行 Student6 s = Test3.stu;//把静态变量的值赋值给一个变量 s.exam(); //通过这个变量调用其中的方法。 //合并 Test3.stu.exam(); System.out.println("Hello World"); } } class Student6{ //实例方法 public void exam(){ System.out.println("考试中。。"); } }
Object中有一个方法toString(),测试后发现:
Sysetm.out.println(引用); //当我们直接输出一个“引用”的时候,println()方法会自动调用“引用.toString()”,然后输出toString()的执行结果。
/* //默认继承Object,Object中有哪些方法呢? public class Object { //注意:当源码中一个方法以“;”结尾,并且修饰符列表中有“native”关键字时 //表示底层调用C++写的dll程序(dll动态链接库文件) private static native void registerNatives(); //静态代码块 static { //调用registerNatives方法 registerNatives(); } //无参数构造方法 @HotSpotIntrinsicCandidate public Object() {} //底层也是调用C++ @HotSpotIntrinsicCandidate public final native Class<?> getClass(); //底层也是调用C++ @HotSpotIntrinsicCandidate public native int hashCode(); //equals方法应该看懂 //public是公开的、boolean是方法的返回值类型、equals是一个方法名,意思是:相等。 //(Object obj) 形参 //只不过目前还不知道这个方法存在的意义。 public boolean equals(java.lang.Object obj) { //方法体 return (this == obj); } //已有对象a,想创建一个和a一模一样的对象,你可以调用这个克隆方法。 //底层也是调用C++ @HotSpotIntrinsicCandidate protected native java.lang.Object clone() throws CloneNotSupportedException; //一会可以测试一下toString()方法 //public 表示公共的、String是返回值类型、toString()方法执行结束之后返回一个字符串。 //toString是方法名,()表示形参个数为0。 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } @HotSpotIntrinsicCandidate public final native void notify(); @HotSpotIntrinsicCandidate public final native void notifyAll(); public final void wait() throws InterruptedException { wait(0L); } public final native void wait(long timeoutMillis) throws InterruptedException; public final void wait(long timeoutMillis, int nanos) throws InterruptedException { if (timeoutMillis < 0) { throw new IllegalArgumentException("timeoutMillis value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos > 0) { timeoutMillis++; } wait(timeoutMillis); } @Deprecated(since="9") protected void finalize() throws Throwable { } } */ // public class ExtendsTest04 { // ExtendsTest04中默认继承Object // ExtendsTest04类当中是有toString()方法 // 不过toString()方法是一个实例方法,需要创建对象才能调用。 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public static void main(String[] args){ //分析这个代码可以执行吗? //ExtendsTest04.toStirng(); //报错 //先new对象 ExtendsTest04 et = new ExtendsTest04(); String retValue = et.toString();//返回String类型的值,定义一个变量接收 System.out.println(retValue);//ExtendsTest04@1b6d3586 //1b6d3586 可以“等同”看做对象在堆内存中的内存地址 //实际上是内存地址经过“哈希算法”得出的十六进制结果 //创建对象 Product1 p = new Product1(); System.out.println(p.toString());//Product1@4554617c System.out.println(100); System.out.println(true); //如果直接输出“引用”呢? //直接输出引用,会自动调用这个引用的toString()方法 System.out.println(p);//Product1@4554617c //println方法会自动调用p的toString()方法 } } class Product1{ /* public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } */ }