-
2021-03-07 14:21:11
子类转父类 (父类引用指向子类对象)
子类可以转换为父类,如下父类FruitTest与其子类AppleTest
classFruitTest {
String str= "FruitTest";public String get() {returnstr;}public void set(String str) {this.str =str;}
}class AppleTest extendsFruitTest {
String str= "AppleTest";
}
FruitTest obj = new AppleTest(); 是正确的
obj.str 结果为"FruitTest",不是子类中的str("AppleTest")。obj的属性变量都是父类的。
obj.get() 得到的是"FruitTest",执行的是父类中的方法,但若是子类重写了父类方法,执行的则是子类的方法
class AppleTest extendsFruitTest {
String str= "AppleTest";public String get() {returnstr;};
}
则obj.get()得到的是"AppleTest" 。
总结:子类可以转换为父类,即父类引用指向子类对象。引用的属性是父类的,方法若果被子类重写则是子类的方法。
父类转子类(子类引用指向父类对象)
父类不可以直接转换为子类,AppleTest obj = new FruitTest(); 是错误的。
AppleTest obj = (AppleTest) new FruitTest(); 编译时也会报错。
FruitTest obj = new AppleTest();
AppleTest test = (AppleTest)obj; 这两句是正确的。
父类若转换为子类,父类引用必须指向的是一个子类对象。实质上是将一个指向子类对象的父类引用改为了子类引用。
更多相关内容 -
java子类调用父类的方法中包含子类重写的实例方法
2020-08-25 15:28:00在本篇文章里小编给大家整理了关于java子类调用父类的方法中包含子类重写的实例方法以及相关知识点,需要的朋友们可以学习下。 -
Java子类对象的实例化过程分析
2020-08-25 14:50:38主要介绍了Java子类对象的实例化过程,结合具体实例形式分析了java子类对象的实例化的步骤、原理、实现方法,需要的朋友可以参考下 -
java子类继承父类实例-披萨的选择实现代码
2020-08-28 11:22:12主要介绍了java子类继承父类实例-披萨的选择实现代码,具有一定借鉴价值,需要的朋友可以参考下。 -
【Java子类与继承(完整版)】
2021-03-25 22:53:12Java子类与继承1 子类与父类1.1 子类1.2 类的树形结构2 子类的继承性2.1 子类和父类在同一包中的继承性2.2 子类和父类不在同一包中的继承性2.3 继承关系(Generalization)的UML图2.4 protected的进一步说明3 子类与...Java子类与继承
1 子类与父类
继承是一种由已有的类创建新类的机制。利用继承,我们可以先创建一个共有属性的一般类,根据该一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。由继承而得到的类称为子类,被继承的类称为父类(超类) 。
Java不支持多重继承(子类只能有一个父类)
习惯地称子类与父类是"is-a”关系。1.1 子类
使用关键字extends来定义一个类的子类,格式如下:
class 子类名 extends 父类名{
…
}
例如:
class Student extends People {
…
}
说明:把Student类定义为People类的子类、People类是Student
类的父类1.2 类的树形结构
Java的类按继承关系形成树形结构这个树形结构中,根节点是Object类( Object是java.lang包中的类),即Object是所有类的祖先类。除了Object类,每个类都有且仅有一个父类,一个类可以有多个或零个子类。如果一个类(除了Object类)的声明中没有使用extends关键字,这个类被系统默认为是
Object的子类,即类声明“class A”与“class A extends Object"是等同的。2 子类的继承性
类可以有两种重要的成员:成员变量和方法。子类的成员中有一部分是子类自己声明定义的,另一部分是从它的父类继承的。所谓子类继承父类的成员变量就是把继承来的变量作为自己的一个成员变量,就好象它们是在子类中直接声明一样,可以被子类中自己定义的任何实例方法操作。所谓子类继承父类的方法就是把继承来的方法作为子类中的一个方法,就好象它们是在子类中直接定义了一样,可以被子类中自己定义的任何实例方法调用。
//子类的继承 class Father { float weight, height; String head; void speak(String s) { System.out.println(s); } } class Son extends Father { String hand, foot; } public class Test { public static void main(String[] args) { Son s = new Son(); } }
2.1 子类和父类在同一包中的继承性
如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法,继承的成员变量或方法的访问权限保持不变。
下面的例子2.1中有4个类: People, Student.java,UniverStudent.java和Example2_1,这些类都没有包名,其中UniverStudent类是Student的子类,Student 是People的子类。程序运行效果
People.javapublic class People { int age,leg = 2,hand = 2; protected void showPeopleMess() { System.out.printf("%d岁,%d只脚,%d只手\t",age,leg,hand); } }
Student.java
public class Student extends People { int number; void tellNumber() { System.out.printf("学号:%d\t",number); } int add(int x,int y) { return x+y; } }
UniverStudent.java
public class UniverStudent extends Student { int multi(int x,int y) { return x*y; } }
Example2_1.java
public class Example2_1 { public static void main(String[] args) { Student zhang = new Student(); zhang.age = 17; //访问继承的成员变量 zhang.number=100101; zhang.showPeopleMess(); //调用继承的方法 zhang.tellNumber(); int x=9,y=29; System.out.print("会做加法:"); int result=zhang.add(x,y); System.out.printf("%d+%d=%d\n",x,y,result); UniverStudent geng = new UniverStudent(); geng.age = 21; //访问继承的成员变量 geng.number=6609; geng.showPeopleMess(); //调用继承的方法 geng.tellNumber(); //调用继承的方法 System.out.print("会做加法:"); result=geng.add(x,y); //调用继承的方法 System.out.printf("%d+%d=%d\t",x,y,result); System.out.print("会做乘法:"); result=geng.multi(x,y); System.out.printf("%d×%d=%d\n",x,y,result); } }
2.2 子类和父类不在同一包中的继承性
如果子类与父类不在同一个包中,则子类只会继承父类public、protected的变量和方法,继承的变量和方法的访问权限保持不变。
2.3 继承关系(Generalization)的UML图
如果一个类是另一个类的子类,那么UML通过使用一个实线连接两个类的UML图来表示二者之间的继承关系,实线的起始端是子类的UML图,终点端是父类的UML图,但终点端使用一个空心的三角形表示实线的结束。
3 子类与对象
3.1 子类对象的特点
子类创建对象时,子类的构造方法总是先调用父类的某个构造方法,完成父类部分的创建;然后再调用子类自己的构造方法,完成子类部分的创建。如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类的不带参数的构造方法。
子类在创建一个子类对象时,不仅子类中声明的成员变量被分配了内存,而且父类的所有的成员变量也都分配了内存空间,但子类只能操作继承的那部分成员变量。
子类可以通过继承的方法来操作子类未继承的变量和方法
例子3.1中,子类ChinaPeople的对象调用继承的方法操作未被子类继承却分配了内存空间的变量
class People { private int averHeight = 166; public int getAverHeight() { return averHeight; } } class ChinaPeople extends People { int height; public void setHeight(int h) { //height = h+averHeight; // 非法,子类没有继承averHeight height = h; } public int getHeight() { return height; } } public class Example5_2 { public static void main(String[] args) { ChinaPeople zhangSan = new ChinaPeople(); System.out.println("子类对象未继承的averageHeight的值是:"+zhangSan.getAverHeight()); zhangSan.setHeight(178); System.out.println("子类对象的实例变量height的值是:"+zhangSan.getHeight()); } }
3.2 关于instanceof运算符
instanceof运算符是Java独有的双目运算符,其左面的操作元是对象,右面的操作元是类,当左面的操作元是右面的类或其子类创建的对象时,instanceof运算的结果是true,否则是false.
class Test { String s; Test() { stu s = new String(); if (s instanceof String) { System.out.println("YES"); } } }
4 成员变量的隐藏和方法重写
4.1 成员变量的隐藏
➢对于子类可以从父类继承的成员变量,只要子类中声明的成员变量和父类中的成员变量同名时,子类就隐藏了继承的成员变量。
➢在子类中要操作这个与父类同名的成员变量时,子类操作的是子类重新声明的这个成员变量。而不是被隐藏掉的。
➢子类对象仍然可以调用从父类继承的方法操作被子类隐藏的成员变量,也就是说,子类继承的方法操作的成员变量一定是被子类继承或者隐藏的成员变量。例子4.1(Example4_1.java)中, Goods类有一 个 名字为weight的double型成员变量,本来子类CheapGoods可以继承这个成员变量,但是子类CheapGoods又重新声明了一个int型的名字为weight的成员变量.
Goods.javapublic class Goods { public double weight; public void oldSetWeight(double w) { weight=w; System.out.println("double型的weight="+weight); } public double oldGetPrice() { double price = weight*10; return price; } }
CheapGoods.java
public class CheapGoods extends Goods { public int weight; public void newSetWeight(int w) { weight=w; System.out.println("int型的weight="+weight); } public double newGetPrice() { double price = weight*10; return price; } }
Example4_1.java
public class Example4_1 { public static void main(String[] args) { CheapGoods cheapGoods=new CheapGoods(); //cheapGoods.weight=198.98; 是非法的,因为子类对象的weight已经是int型 cheapGoods.newSetWeight(198); System.out.println("对象cheapGoods的weight的值是:"+cheapGoods.weight); System.out.println("cheapGoods用子类新增的优惠方法计算价格:"+ cheapGoods.newGetPrice()); cheapGoods.oldSetWeight(198.987); //子类对象调用继承的方法操作隐藏的double型变量weight System.out.println("cheapGoods使用继承的方法(无优惠)计算价格:"+ cheapGoods.oldGetPrice()); } }
注意:子类继承的方法只能操作子类继承和隐藏的成员变量,子类新定义的方法可以操作子类继承和子类新声明的成员变量,但无法操作子类隐藏的变量(需要使用super关键字操作子类隐藏的成员变量)
4.2 方法重写
同样,子类通过重写可以隐藏已继承的实例方法。
1.重写的语法规则
如果子类继承了父类的实例方法,那么子类就有权利重写这个方法。
方法重写是指:子类中定义一个方法,这个方法的类型和父类的方法的类型一致或是父类方法的类型的子类型,且这个方法的名字、参数个数、参数的类型和父类的方法完全相同.
2.重写的目的
子类通过方法的重写可以隐藏继承的方法,子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为。
3.重写后方法的调用
子类创建的一个对象,如果子类重写了父类的方法,则运
行时系统调用的是子类重写的方法;
子类创建的一个对象,如果子类未重写父类的方法,则运
行时系统调用的是子类继承的方法;
4.重写的注意事项
重写父类的方法时,不允许降低方法的访问权限,但可以提高访问权限(访问限制修饰符按访问权限从高到低的排列顺序是:public、protected、 友好的、private。 )在下面的例子4_2(Example4_2. java)中,ImportantUniversity是University类的子类,子类重写了父类的enterRule0方法
University.java
public class University { void enterRule(double math,double english,double chinese) { double total=math+english+chinese; if(total>=180) System.out.println("考分"+total+"达到大学最低录取线"); else System.out.println("考分"+total+"未达到大学最低录取线"); } }
ImportantUniversity.java
public class ImportantUniversity extends University{ void enterRule(double math,double english,double chinese) { double total=math+english+chinese; if(total>=220) System.out.println("考分"+total+"达到重点大学录取线"); else System.out.println("考分"+total+"未达到重点大学录取线"); } }
Example4_2.java
public class Example4_2 { public static void main(String args[]) { double math=64,english=76.5,chinese=66; ImportantUniversity univer = new ImportantUniversity(); univer.enterRule(math,english,chinese); //调用重写的方法 math=89; english=80; chinese=86; univer = new ImportantUniversity(); univer.enterRule(math,english,chinese); //调用重写的方法 } }
5 super关键字
5.1 用super操作被隐藏的成员变量和方法
➢子类可以隐藏从父类继承的成员变量和方法,如果在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super.比如super.x、super.play() 就是访问和调用被子类隐藏的成员变量x和方法play()
例子5.1中,子类使用super访问和调用被子类隐藏的成员变量和方法。class Sum { int n; float f() { float sum=0; for(int i=1;i<=n;i++) sum=sum+i; return sum; } } class Average extends Sum { int n; float f() { float c; super.n=n; c=super.f(); return c/n; } float g() { float c; c=super.f(); return c/2; } } public class Example5_1 { public static void main(String args[]) { Average aver=new Average(); aver.n=100; float resultOne=aver.f();//代码1 float resultTwo=aver.g();//代码2 System.out.println("resultOne="+resultOne); System.out.println("resultTwo="+resultTwo); } }
上述例子中如果交换代码1和代码2,则输出为:
resultOne=50.5
resultTwo=0.05.2 用super调用父类的构造方法
子类不继承父类的构造方法,因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字super来表示,而且super必须是子类构造方法中的头一条语句。
注:
创建子类对象时,子类总是按层次结构从上到下的顺序调用所有超类的构造函数,默认调用父类中没有参数的构造方法。如果父类没有不带参数的构造方法,则在子类的构造方法中必须明确的告诉调用父类的某个带参数的构造方法。例子5.2中,UniverStudent是Student的子类,UniverStudent子类
在构造方法中使用了super关键字class Student { int number;String name; Student() { } Student(int number,String name) { this.number=number; this.name=name; System.out.println("我的名字是:"+name+ "学号是:"+number); } } class UniverStudent extends Student { boolean 婚否; UniverStudent(int number,String name,boolean b) { super(number,name); 婚否=b; System.out.println("婚否="+婚否); } } public class Example5_1 { public static void main(String args[]) { UniverStudent zhang=new UniverStudent(9901,"何晓林",false); } }
6 final关键字
final关键字可以修饰类、成员变量、方法中的局部变量和方法。
可以使用final将类声明为final类。final类不能 被继承,即不能有子类。
如:
final class A {
}
如果用final修饰父类中的一个方法,那么这个方法不允许子类重写。
一如果成员变量或局部变量被修饰为final的,就是常量。**例6 **
class A { final double PI=3.1415926;// PI是常量 public double getArea(final double r) { return PI*r*r; } public final void speak() { System.out.println("您好,How's everything here ?"); } } public class Example6 { public static void main(String args[]) { A a=new A(); System.out.println("面积:"+a.getArea(100)); a.speak(); } }
7 对象的上转型对象
假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,称对象a是对象b的上转型对象,比如:
A a; a = new B(); 或者 A a; B b = new B(); a = b;
上转型对象的使用
1.上转型对象不能操作子类新增的成员变量;不能调用子类新增的方法。
2.上转型对象可以访问子类继承或隐藏的成员变量,也可以调用子类继承的方法或子类重写的实例方法。
3.如果子类重写了父类的某个实例方法后,当用上转型对象调用这个实例方法时一定是调用了子类重写的实例方法。**例7 **
class 类人猿 { void crySpeak(String s) { System.out.println(s); } } class People extends 类人猿 { void computer(int a,int b) { int c=a*b; System.out.println(c); } void crySpeak(String s) { System.out.println("***"+s+"***"); } } public class Example7 { public static void main(String args[]) { 类人猿 monkey; People geng = new People(); monkey = geng ; //monkey是People对象geng的上转型对象 monkey.crySpeak("I love this game");//等同于geng.crySpeak("I love this game"); People people=(People)monkey; //把上转型对象强制转化为子类的对象 people.computer(10,10); } }
注意:monkey.crySpeak("I love this game"); 得到的是:***I love this game*** 而不是:I love this game,因为monkey调用的是子类的重写方法crySpeak monkey.computer(10,10);是错误的,因为computer方法是子类新增的方法
1、不要把父类创建的对象和子类对象的上转型对象混淆;
2、可以将对象的上转型对象再强制转换到一个子类对象,这时,该子类对象又具备了子类所有的属性和功能;
3、不可以将父类创建的对象的引用赋值于子类声明的对象;
4、如果子类重写了父类的静态方法,那么子类对象的.上转型对象不能调用子类重写的静态方法,只能调用父类的静态方法。8 继承与多态
多态性就是指父类的某个方法被其子类重写,可以各自产生自己的功能行为。
class 动物 { void cry() { } } class 狗 extends 动物 { void cry() { System.out.println("汪汪....."); } } class 猫 extends 动物 { void cry() { System.out.println("喵喵....."); } } public class Example5_1 { public static void main(String args[]) { 动物 animal; animal = new 狗(); animal.cry(); animal=new 猫(); animal.cry(); } }
9 abstract类和abstract方法
用关键字abstract修饰的类称为abstract类(抽象类)。
例如:
abstract class A {
}
用关键字abstract修饰的方法称为abstract方法(抽象方法)
例如:
abstract int min(int x,int y);abstract类有如下特点
1、和普通的类相比,abstract类里可以有abstract方法。也可以没有。对于abstract方法, 只允许声明,不允许实现,而且不允许使用final修饰abstract方法。
2、对于abstract类,不能使用new运算符创建该类的对象,只能产生其子类,由子类创建对象。
3、如果一个非abstract类是abstract类的子类,它必须具体实现父类的所有的abstract方法。理解的关键点是:
(1)抽象类可以抽象出重要的行为标准,该行为标准用抽象方法来表示。即抽象类封装了子类必需要有的行为标准。
(2)抽象类声明的对象可以成为其子类的对象的上转型对象,调用子类重写的方法,即体现子类根据抽象类里的行为标准给出的具体行为。开发者可以把主要精力放在一个应用中需要那些行为标准(不用关心行为的细节),不仅节省时间,而且非常有利于设计出易维护、易扩展的程序。抽象类中的抽象方法,可以由子类去实现,即行为标准的实现由子类完成。
例9使用了abstract类封装了男孩对女朋友的行为要求,即封装了他要找的任何具体女朋友都应该具有的行为。
abstract class GirlFriend {//抽象类,封装了两个行为标准 abstract void speak(); abstract void cooking(); } class ChinaGirlFriend extends GirlFriend { void speak(){ System.out.println("你好"); } void cooking(){ System.out.println("水煮鱼"); } } class AmericanGirlFriend extends GirlFriend { void speak(){ System.out.println("hello"); } void cooking(){ System.out.println("roast beef"); } } class Boy { GirlFriend friend; void setGirlfriend(GirlFriend f){ friend = f; } void showGirlFriend() { friend.speak(); friend.cooking(); } } public class Example9{ public static void main(String[] args) { GirlFriend girl = new ChinaGirlFriend(); //girl是上转型对象 Boy boy = new Boy(); boy.setGirlfriend(girl); boy.showGirlFriend(); girl = new AmericanGirlFriend(); //girl是上转型对象 boy.setGirlfriend(girl); boy.showGirlFriend(); } }
10 面向抽象编程
在设计一个程序时,可以先声明一个abstract类,通过在类中声明若干个abstract方法,表明这些方法在整个系统设计中的重要性,方法体的内容细节由它的非abstract子类去完成。.然后利用多态实现编程。使用多态进行程序设计的核心技术是使用方法重写和上转型对象,即将abstract类声明对象作为其子类的上转型对象,那么这个上转型对象就可以调用子类重写的方法。
所谓面向抽象编程,是指当设计某种重要的类时,不让该类面向具体的类,而是面向抽象类,即所设计类中的重要数据是抽象类声明的对象,而不是具体类声明的对象。例题:
Pillar类就是面向抽象类Geometry, Cirle和Rectangle 都是Geometry的子类. Application.java 可以用Pillar类创建出具有矩形底或圆形底的柱体了。首先编写一个抽象类Geometry,该抽象类中定义了一个抽象的getArea()方法,Geometry类如下:
Geometry.javapublic abstract class Geometry { //抽象类 public abstract double getArea(); }
上述抽象类将所有计算面积的算法抽象为一个标识:getArea(),即抽象方法,不再考虑算法细节。
现在Pillar类的设计者可以面向Geometry类编写代码,即Pillar类应该把Geometry对象
作为自己的成员,该成员可以调用Geometry的子类重写的getArea()方法。这样一来, Pillar类就可以将计算底面积的任务指派给Geometry类的子类的实例(用户的各种需求将由不同的子类去负责)。以下Pillar类的设计不再依赖具体类,而是面向Geometry类,即Pillar类中的bottom是
用抽象类Geometry声明的对象,而不是具体类声明的对象。重新设计的Pillar类的代码如下:
Pillar.javapublic class Pillar { Geometry bottom; //bottom是抽象类Geometry声明的变量 double height; Pillar(Geometry bottom, double height) { this.bottom = bottom; this.height = height; } public double gerVolume() { if (bottom == null) { System.out.println("没有底,无法计算体积"); return -1; } return bottom.getArea() * height; //bottom可以调用子类重写的getArea方法 } }
下列Circle和Rectangle类都是Geometry的子类,二者都必须重写Geometry类的getArea()方法来计算各自的面积。
Circle.java
public class Circle extends Geometry { // 圆类 double r; Circle(double r) { this.r = r; } public double getArea() { return (3.14 * r * r); } }
Rectangle.java
public class Rectangle extends Geometry { double a, b; Rectangle(double a, double b) { this.a = a; this.b = b; } public double getArea() { return a * b; } }
注意到,当增加了Circle和Rectangle类后,我们不必修改Pillar类的代码,现在,我们就可以用Pillar类创建出具有矩形或者圆底的柱体了,如下列Application.java所示:
public class Application { //主类 public static void main(String[] args) { Pillar pillar; Geometry bottom = null; pillar = new Pillar(bottom, 100);//没有底的柱体 System.out.println("体积" + pillar.gerVolume()); bottom = new Rectangle(12, 22); pillar = new Pillar(bottom, 58);//pillar是具有矩形底的柱体 System.out.println("体积" + pillar.gerVolume()); bottom = new Circle(10); pillar = new Pillar(bottom, 58);//pillar是具有圆形底的柱体 System.out.println("体积" + pillar.gerVolume()); } }
通过面向抽象来设计Pillar类,使得该Pillar类不再依赖具体类,因此每当系统增加新的
Geometry的子类时,例如增加一个 Triangle子类,那么我们不需要修改Pillar类的任何代码,就可以使用Pillar 创建出具有三角形底的柱体。11 开-闭原则
所谓“开闭原则”(Open-Closed Principle) 就是让设计的系统应当对扩展开放,对修改关闭。
在设计系统时,应当首先考虑到用户需求的变化,将应对用户变化的部分设计为对扩展开放,而设计的核心部分是经过精心考虑之后确定下来的基本结构,这部分应当是对修改关闭的,即不能因为用户的需求变化而再发生变化,因为这部分不是用来应对需求变化的。如果系统的设计遵守了“开-闭原则”,那么这个系统一定是易维护的,因为在系统中增加新的模块时,不必去修改系统中的核心模块。
-
java 子类对象赋值给父类对象的使用
2011-12-12 18:37:05java 子类对象赋值给父类对象的使用,包括代码及详解,个人笔记 -
Java子类父类属性的覆盖
2021-02-13 01:43:09Java codeclass ParentClass {public int i = 10;}public class SubClass extends ParentClass {public int i = 30;public static void main(String[] args) {ParentClass parentClass = new SubClass();SubClass su...Java code
class ParentClass {
public int i = 10;
}
public class SubClass extends ParentClass {
public int i = 30;
public static void main(String[] args) {
ParentClass parentClass = new SubClass();
SubClass subClass = new SubClass();
System.out.println(parentClass.i + subClass.i);
}
}
控制台的输出结果是多少呢?20?40?还是60?
变量,或者叫做类的属性,在继承的情况下,如果父类和子类存在同名的变量会出现什么情况呢?这就是这道题要考查的知识点——变量(属性)的覆盖。
这个问题虽然简单,但是情况却比较复杂。因为我们不仅要考虑变量、静态变量和常量三种情况,还要考虑private、friendly(即不加访问修饰符)、protected和public四种访问权限下对属性的不同影响。
我们先从普通变量说起。依照我们的惯例,先来看一段代码:
Java code
class ParentClass {
private String privateField = "父类变量--private";
/* friendly */String friendlyField = "父类变量--friendly";
protected String protectedField = "父类变量--protected";
public String publicField = "父类变量--public";
// private的变量无法直接访问,因此我们给他增加了一个访问方法
public String getPrivateFieldValue() {
return privateField;
}
}
public class SubClass extends ParentClass {
private String privateField = "子类变量--private";
/* friendly */String friendlyField = "子类变量--friendly";
protected String protectedField = "子类变量--protected";
public String publicField = "子类变量--public";
// private的变量无法直接访问,因此我们给他增加了一个访问方法
public String getPrivateFieldValue() {
return privateField;
}
public static void main(String[] args) {
// 为了便于查阅,我们统一按照private、friendly、protected、public的顺序
// 输出下列三种情况中变量的值
// ParentClass类型,ParentClass对象
ParentClass parentClass = new ParentClass();
System.out.println("ParentClass parentClass = new ParentClass();");
System.out.println(parentClass.getPrivateFieldValue());
System.out.println(parentClass.friendlyField);
System.out.println(parentClass.protectedField);
System.out.println(parentClass.publicField);
System.out.println();
// ParentClass类型,SubClass对象
ParentClass subClass = new SubClass();
System.out.println("ParentClass subClass = new SubClass();");
System.out.println(subClass.getPrivateFieldValue());
System.out.println(subClass.friendlyField);
System.out.println(subClass.protectedField);
System.out.println(subClass.publicField);
System.out.println();
// SubClass类型,SubClass对象
SubClass subClazz = new SubClass();
System.out.println("SubClass subClazz = new SubClass();");
System.out.println(subClazz.getPrivateFieldValue());
System.out.println(subClazz.friendlyField);
System.out.println(subClazz.protectedField);
System.out.println(subClazz.publicField);
}
}
这段代码的运行结果如下:
ParentClass parentClass = new ParentClass();
父类变量--private
父类变量--friendly
父类变量--protected
父类变量--public
ParentClass subClass = new SubClass();
子类变量--private
父类变量--friendly
父类变量--protected
父类变量--public
SubClass subClazz = new SubClass();
子类变量--private
子类变量--friendly
子类变量--protected
子类变量--public
从上面的结果中可以看出,private的变量与其它三种访问权限变量的不同,这是由于方法的重写(override)而引起的。关于重写知识的回顾留给以后的章节,这里我们来看一下其它三种访问权限下变量的覆盖情况。
分析上面的输出结果就会发现,变量的值取决于我们定义的变量的类型,而不是创建的对象的类型。
在上面的例子中,同名的变量访问权限也是相同的,那么对于名称相同但是访问权限不同的变量,情况又会怎样呢?事实胜于雄辩,我们继续来做测试。由于private变量的特殊性,在接下来的实验中我们都把它排除在外,不予考虑。
由于上面的例子已经说明了,当变量类型是父类(ParentClass)时,不管我们创建的对象是父类(ParentClass)的还是子类(SubClass)的,都不存在属性覆盖的问题,因此接下来我们也只考虑变量类型和创建对象都是子类(SubClass)的情况。
Java code
class ParentClass {
/* friendly */String field = "父类变量";
}
public class SubClass extends ParentClass {
protected String field = "子类变量";
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(subClass.field);
}
}
运行结果:
子类变量
Java代码
class ParentClass {
public String field = "父类变量";
}
public class SubClass extends ParentClass {
protected String field = "子类变量";
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(subClass.field);
}
}
运行结果:
子类变量
上面两段不同的代码,输出结果确是相同的。事实上,我们可以将父类和子类属性前的访问修饰符在friendly、protected和public之间任意切换,得到的结果都是相同的。也就是说访问修饰符并不影响属性的覆盖,关于这一点大家可以自行编写测试代码验证。
对于静态变量和常量又会怎样呢?我们继续来看:
Java code
class ParentClass {
public static String staticField = "父类静态变量";
public final String finalField = "父类常量";
public static final String staticFinalField = "父类静态常量";
}
public class SubClass extends ParentClass {
public static String staticField = "子类静态变量";
public final String finalField = "子类常量";
public static final String staticFinalField = "子类静态常量";
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(SubClass.staticField);
System.out.println(subClass.finalField);
System.out.println(SubClass.staticFinalField);
}
}
运行结果如下:
子类静态变量
子类常量
子类静态常量
虽然上面的结果中包含“子类静态变量”和“子类静态常量”,但这并不表示父类的“静态变量”和“静态常量”可以被子类覆盖,因为它们都是属于类,而不属于对象。
上面的例子中,我们一直用对象来对变量(属性)的覆盖做测试,如果是基本类型的变量,结果是否会相同呢?答案是肯定的,这里我们就不再一一举例说明了。
最后,我们来做个总结。通过以上测试,可以得出一下结论:
由于private变量受访问权限的限制,它不能被覆盖。
属性的值取父类还是子类并不取决于我们创建对象的类型,而是取决于我们定义的变量的类型。
friendly、protected和public修饰符并不影响属性的覆盖。
静态变量和静态常量属于类,不属于对象,因此它们不能被覆盖。
常量可以被覆盖。
对于基本类型和对象,它们适用同样的覆盖规律。
最后我们再回到篇首的那道题,我想答案大家都已经知道了,结果是40。
-
Java子类继承父类详解
2021-02-12 11:46:34SubT can run too SubT can run too SubT can fly 从上述结果可以看出,当一个父类引用指向了一个子类的对象时,调用的方法为子类复写后的方法,而非父类方法,正式这一特性大大地拓展了java的多态性 附一个讲的...别和我说你真的懂了继承,先来看下面的代码,回答出我的问题再说
代码很简单,如下:
父类:
public class T {
public void run()
{
System.out.println("T can run");
}
public static void main(String args[])
{
T t = new SubT();
t.run();
t.fly();
SubT subT = (SubT)t;
subT.run();
subT.fly();
}
}
子类:
public class SubT extends T{
public void run()
{
System.out.println("SubT can run too");
}
public void fly()
{
System.out.println("SubT can fly");
}
}
首先,上述代码可以正常编译乃至运行吗?
其次,能够执行其结果是?不能编译或执行的原因在哪个地方?
上面这个例子是很典型的子类继承父类并重写run方法,添加了新的fly方法,而调用的时候去声明一个父类引用去指向一个子类对象
首先,上述代码是无法编译通过的,因为一个父类的引用无法去调用子类独有的方法或者被子类复写后的方法,故t.fly()这个调用时违法的
好的,那么我们把这句注释掉,输出结果是什么呢?
SubT can run too
SubT can run too
SubT can fly
从上述结果可以看出,当一个父类引用指向了一个子类的对象时,调用的方法为子类复写后的方法,而非父类方法,正式这一特性大大地拓展了java的多态性
附一个讲的比较详细的链接:父类引用指向子类对象
-
怎么建立java子类
2021-02-12 15:57:26建立java子类的方法:首先调用父类中的构造函数进行初始化;然后在父类初始化完毕后,对子类的属性进行显示初始化;最后进行子类构造函数的特定初始化。建立子类过程:Java在构造函数中,第一行会先调用父类中构造... -
java子类和父类属性重复问题
2021-02-28 08:53:26java 子类继承 父类, 但子类中 包含和父类相同 属性 ,给子类赋值之后,父类的相同的属性值还是空的。类定义如下:public class Person {private String name;private String age;// ignore getter and setter}... -
JAVA子类继承父类
2021-03-01 06:34:011、类的继承知识点 (1)java不支持多重继承,也就是说子类至多只能有一个父类 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法 (3)子类中定义的成员变量和父类中定义的成员变量... -
Java子类与父类之间的类型转换
2021-02-12 14:18:00从子类向父类的转换不需要什么限制,只需直接蒋子类实例赋值给父类变量即可,这也是Java中多态的实现机制。2.向下转换在父类变量调用子类特有的、不是从父类继承来的方法和变量时,需要父类变量向子类转换。为什么要... -
Java 子类和父类同名属性
2022-01-20 11:23:21继承的本质/内存图 属性访问的顺序: 案例1 public class Test { public static void ... //子类对象 b.i = 200; b.B(); } } class A { int i = 10; public void A() { System.out.println(i); } } class B e -
Java子类继承父类私有方法
2021-10-12 17:09:32在Java继承关系中,子类其实继承了父类的全部方法和属性,只是没有权限访问父类的私有成员。 import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; class Father{ private String name... -
java子类调用父类的方法
2021-03-22 17:40:41当一个类继承于另一个类,子类中没有父类的方法时,用子类的对象调用方法时,会首先在子类中查找,如果子类中没有该方法,再到父类中查找。 当一个方法只在父类中定义时,调用该方法时会使用父类中的属性。 如果该... -
JAVA子类继承父类时的构造方法
2021-12-03 16:52:22在 Java 中,无论是 explicit 还是 implicit 方式,都要求在子类的构造方法中调用其父类的构造方法。如果父类无构造方法(其实是一个默认无参的构造方法),那么子类的构造方法中会自动进行调用;如果父类有自己的构造... -
java子类调用父类构造方法
2021-04-20 10:00:52java子类调用父类构造方法 来源:https://www.cnblogs.com/sunnychuh/archive/2011/09/09/2172131.html(本人用来方便查看笔记,不用于其他任何用途) java继承中对构造函数是不继承的,只是调用(隐式或显式)。 ... -
java子类中如何访问和修改父类成员
2021-02-25 20:12:07展开全部根据父类成员bai的访问权限修饰词分为两du种情况:①父类成zhi员域由daoprivate修饰,那么在子类中不能直接访专问父属类成员域,但是可以通过父类中的公共方法访问以及修改父类成员域。如:class FatherClass... -
java代码-java子类继承
2021-07-16 13:25:44java代码-java子类继承 -
JAVA子类调用父类构造方法
2021-03-06 16:59:23以下语句中MyException类继承了java.lang.Exception类。public class MyException extends Exception{} //MyException类只有一个隐含的默认构造方法尽管在Exception类中定义了如下形式的构造方法:public Exception... -
Java子类重写父类的方法
2020-05-20 21:35:49Java子类重写父类的方法 一、方法名一致 //这是父类 public class SuperClass { public void test(){ System.out.println("我是父类的方法"); } } //这是子类 public class SubClass extends SuperClass{ //... -
java子类调用父类的方法是什么
2021-02-06 21:34:33java子类调用父类的方法:1、子类的对象调用方法时,会首先在子类中查找,如果子类中没有该方法,再到父类中查找;2、如果该方法中又调用了其他方法,那么还是按照之前的顺序,先在子类中查找,再在父类中查找。... -
java 子类与父类
2021-02-12 08:55:55子类是由继承得到的类,被继承的类就是父类,子类与...子类与父类在同个包中:子类继承父类除了private成员子类与父类在不同包中:子类继承父类除了private、友好成员protected成员:若子类与祖先类同包,子类可访... -
java子类调用父类的构造方法
2021-04-16 16:45:12调用父类中的方法(无论是类方法还是实例方法都可以,除此调用实例方法的还可以在方法内部实例化再调用) ** 总之:存在继承关系的子类初始化,必须先调用父类构造器,你自己不显式调用,Java就强制默认让你调用父类...