Java笔记 —— 继承
Java笔记 —— 继承
h2{
color: #4ABCDE;
}
a{
text-decoration: none!important;
}
a:hover{
color: red !important;
text-decoration: underline !important;
}
pre{
border: solid 1px #CCCCCC;
border-radius: 3px;
background-color: #F8F8F8;
margin: 15px;
overflow: auto;
white-space: pre;
font-size: 13px;
font-family: consolas, courier, monospace;
line-height: 20px;
padding: 6px 10px;
tab-size: 4;
}
p.textRight{
text-align: right;
}
p.header{
color: #787878;
font-size: 20px;
font-family: 楷体, "微软雅黑", arial;
font-weight: bold;
}
二、super 关键字
1)第一种用法:super 关键字是父类对象的引用
package com.example;
public class Person{ // 父类
public String name="张三";
public int age = 20;
public void speak(){
System.out.println("Person: speak()");
}
public void cry(){
System.out.println("Person: cry()");
}
}
package com.example;
public class Man extends Person{ // 子类
public void speak(){
System.out.println("Man: speak()");
super.speak(); // 调用父类的 speak
cry(); // 调用父类的 cry
System.out.println("name: " + name); // 调用父类的 name
System.out.println("age: " + super.age); // 调用父类的 age
}
}
package com.example;
public class Test{
public static void main(String[] args){
Man m = new Man();
m.speak();
}
}
运行结果: Man: speak()
Person: speak()
Person: cry()
name: 张三
age: 20
- 父类和子类中都有 speak 方法,所以子类中想要调用父类的 speak 方法时,必须要用 super 关键字(这种情况是子类对父类的方法进行了重写)
- 其他情况可以使用 super 关键字也可以不使用,例如:例子中的 cry(), name, super.age
- 其实在创建子类对象的时候,父类对象会先被创建,而且父类对象被包裹在子类对象中(可以想象成在 Man 对象中有 Person super = new Person() 这样的代码行,这里的 super 就是父类对象的引用)
2)第二种用法:super() 或者 super(参数列表) 是父类的构造器
例1:
package com.example;
public class Person{ // 父类
public Person(){
System.out.println("Person()");
}
}
package com.example;
public class Man extends Person{ // 子类
public Man(){
super(); // 父类构造器
System.out.println("Man()");
// super(); //error
}
}
package com.example;
public class Test{
public static void main(String[] args){
new Man();
}
}
运行结果: Person()
Man()
- 父类构造器只能在子类构造器中调用,不能在子类的方法中调用
- 父类构造器只能位于子类构造器的第一行
- 每个子类构造器只能调用一个父类构造器
例2:
package com.example;
public class Person{ // 父类
public Person(int i){
System.out.println("Person" + "(" + i + ")");
}
public Person(String str){
System.out.println("Person" + "(" + str + ")");
}
}
package com.example;
public class Man extends Person{ // 子类
public Man(){
super(1); // 调用父类构造器
System.out.println("Man()");
}
public Man(int i){
super("张三"); // 调用父类构造器
System.out.println("Man" + "(" + i + ")");
}
public Man(String str){
super(2); // 调用父类构造器
System.out.println("Man" + "(" + str + ")");
}
}
package com.example;
public class Test{
public static void main(String[] args){
new Man();
}
}
运行结果: Person(1)
Man()
- 如果我们没有给类创建构造器,编译器会为该类自动创建一个默认构造器(无参构造器),该操作在编译时完成,我们看不见。如果我们给类创建了构造器,那么编译器便不会再为类创建默认构造器
- 当父类中含有默认构造器时,编译器会在子类的构造器中自动调用父类的默认构造器,以完成父类的初始化,该操作也是在编译时完成的,我们看不见
- 当父类中含有无参构造器时,编译器也会在子类构造器中自动调用父类的无参构造器
- 当父类中只含有有参构造器时,编译器不会在子类构造器中自动调用父类的构造器,此时我们必须在子类的所有构造器中都对父类中的一个构造器进行调用,否则编译时会报错,例如:例子中子类 Man 中的每一个构造器都调用了父类的构造器
- 总结:在继承关系中,父类最好不创建构造器或者在创建多个构造器时要创建一个无参构造器,这样才不用每个子类的构造器都对父类的构造器进行调用
[ 返回顶部 ]
三、访问控制权限
1)Java 的访问控制权限有 public,protected,<default>,private 其中如果没有涉及继承关系时,protected 和 <default> 都只能在包内访问
package net.example;
public class S{
public int i = 10;
protected double d = 51.2;
String str1 = "张三"; // <default>
private String str2 = "李四";
}
package com.example;
public class T{
public int i = 10;
protected double d = 51.2;
String str1 = "张三"; // <default>
private String str2 = "李四";
}
package com.example;
import net.example.S; // 导入 S 类 public class Test{
public static void main(String[] args){
S s1 = new S();
System.out.println("S: " + s1.i);
//System.out.println("S: " + s1.d); // error
//System.out.println("S: " + s1.str1); // error
//System.out.println("S: " + s1.str2); // error T t1 = new T();
System.out.println("T: " + t1.i);
System.out.println("T: " + t1.d);
System.out.println("T: " + t1.str1);
//System.out.println("T: " + t1.str2); // error
}
}
运行结果: S: 10
T: 10
T: 51.2
T: 张三
- private 可以跨包访问
- 没有继承关系时,protected 和 <default> 都只能在包内访问。例子中 Test 和 T 在同一个包,Test 和 S 在不同的包,所以 s1.d 和 s1.str1 都不能通过编译,而 t1.d 和 t1.str1 可以通过编译
- private 只能在同一个类中被访问
2)子类可以访问父类中用 protected 限制的属性和方法,即使子类和父类不在同一个包内
package net.example;
public class Animals{ // 父类
protected int age = 2;
String name = "旺财"; // <default>
protected void bark(){
System.out.println("汪汪");
}
}
package com.example;
import net.example.Animals; // 导入 Animals 类 public class Dogs extends Animals{ // 子类
public Dogs(){
System.out.println(age);
//System.out.println(name); // error
bark();
}
}
package com.example;
public class Test{
public static void main(String[] args){
new Dogs();
}
}
运行结果: 2
汪汪
- 父类中的 name 属性的访问控制权限为 <default> ,所以子类不能调用该属性
- protected 访问控制权限可以保证只有继承者才能对父类的属性和方法进行访问,当然这是在跨包的情况下,如果某一个类和父类在同一个包,就算这个类不继承父类,那么也可以随意访问父类中由 protected 限制的属性和方法
package com.example;
public class Person{ // 父类
public void p1(){
System.out.println("Person: p1");
}
protected void p2(){
System.out.println("Person: p2");
}
void p3(){
System.out.println("Person: p3");
}
private void p4(){
System.out.println("Person: p4");
}
}
package com.example;
public class Man extends Person{ // 子类
public void p1(){
System.out.println("Man: p1");
}
/* public void p2(){
System.out.println("Man: p2");
} */
protected void p2(){
System.out.println("Man: p2");
}
/* void p2(){ // error, protected 的访问控制权限比 <default> 的高
System.out.println("Man: p2");
} */
/* public void p3(){
System.out.println("Man: p3");
}
protected void p3(){
System.out.println("Man: p3");
} */
void p3(){
System.out.println("Man: p3");
}
/* public void p4(){
System.out.println("Man: p4");
}
protected void p4(){
System.out.println("Man: p4");
}
void p4(){
System.out.println("Man: p4");
} */
private void p4(){
System.out.println("Man: p4");
}
}
package com.example;
public class Test{
public static void main(String[] args){
Man m = new Man();
m.p1();
m.p2();
m.p3();
//m.p4(); // error
}
}
运行结果: Man: p1
Man: p2
Man: p3
- 子类 Man 中的 p2 方法不能用 <default> 访问控制权限进行重写,因为 protected 的控制权限比较高
- Test 类中不能调用 m.p4() 因为 p4() 的访问控制权限是 private,只能在类的内部进行调用
- 子类重写父类的方法时,只要重写方法的访问控制权限比父类中的高就行,比如:父类中的 p2 方法由 protected 限制,所以子类 Man 中重写父类的 p2 方法时,可以是public 或者是 protected,但不能是 <default> 和 private
[ 返回顶部 ]
四、初始化顺序
1)初始化顺序:父类静态属性 -> 子类静态属性 -> 父类非静态属性 -> 父类构造器调用 -> 子类非静态属性 -> 子类构造器调用
package com.example;
public class T{
public T(int i){
System.out.println("T" + "(" + i + ")");
}
}
package com.example;
public class Person{ // 父类
public static T t1 = new T(1); // 静态属性
public T t2 = new T(2); // 非静态属性
public Person(){
System.out.println("Person()");
}
public static T t3 = new T(3); // 静态属性
}
package com.example;
public class Man extends Person{ // 子类
public static T t4 = new T(4); // 静态属性
public T t5 = new T(5); // 非静态属性
public Man(){
System.out.println("Man()");
}
public static T t6 = new T(6); // 静态属性
}
package com.example;
public class Test{
public static void main(String[] args){
new Man();
}
}
运行结果: T(1)
T(3)
T(4)
T(6)
T(2)
Person()
T(5)
Man()
[ 返回顶部 ]
五、@Override 与方法重写
1)Java 为了保证方法重写时不会出现误写成方法重载的情况,所以引入了 @Override
package com.example;
public class Person{ // 父类
public void speak(int i){
System.out.println("Person: speak" + "(" + i + ")");
}
}
package com.example;
public class Man extends Person{ // 子类
/* @Override
public void speak(String str){
System.out.println("Man: speak" + "(" + str + ")");
} */ // error,用了 @Override ,那么 @Override 下面的方法必须是方法重写,否则编译时会出错
@Override
public void speak(int i){
System.out.println("Man: speak" + "(" + i + ")");
}
}
package com.example;
public class Test{
public static void main(String[] args){
Man m = new Man();
m.speak(10);
}
}
运行结果: Man: speak(10)
[ 返回顶部 ]
六、继承抽象类
1)继承抽象类时,如果父类中有抽象方法,那么子类必须全部重写父类中的抽象方法
package com.example;
public abstract class Person{
public abstract void p1(); // 抽象方法
public abstract void p2();
public void p3(){
System.out.println("Person: p3()");
}
public void p4(){
System.out.println("Person: p4()");
}
}
package com.example;
public class Man extends Person{
@Override
public void p1(){
}
@Override
public void p2(){
}
}
[ 返回顶部 ]
七、final 关键字
1)由 final 关键字修饰的类不能被继承,例如:public final class Person{}
2)在继承关系中,如果父类的方法由 final 关键字修饰,那么该方法将不能被子类重写
[ 返回顶部 ]
参考资料:
《Java 编程思想》第4版
End~
Java笔记 —— 继承的更多相关文章
- Java笔记: 继承成员覆盖和隐藏
在扩展类时,既可以向类中添加新的成员,也可以重新定义现有的成员.重定义现有成员的具体效果取决于成员的类型.本文不会详细的介绍概念,只简要总结覆盖(overriding,也叫重写)和隐藏(hiding) ...
- [Java笔记]继承
继承只是继承框架,而数据没有继承!. 继承不改变父类数据!
- java学习笔记 --- 继承
继承 (1)定义:把多个类中相同的成员给提取出来定义到一个独立的类中.然后让这多个类和该独立的类产生一个关系, 这多个类就具备了这些内容.这个关系叫继承. (2)Java中如何表示继承呢?格式 ...
- Java学习笔记二十三:Java的继承初始化顺序
Java的继承初始化顺序 当使用继承这个特性时,程序是如何执行的: 继承的初始化顺序 1.初始化父类再初始子类 2.先执行初始化对象中属性,再执行构造方法中的初始化 当使用继承这个特性时,程序是如何执 ...
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- java笔记整理
Java 笔记整理 包含内容 Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...
- Java笔记 —— 方法重载和方法重写
Java笔记 -- 方法重载和方法重写 h2{ color: #4ABCDE; } a{ text-decoration: none !important; } a:hover{ color: red ...
- Java笔记 —— 初始化
Java笔记 -- 初始化 h2{ color: #4ABCDE; } a{ text-decoration: none !important; } a:hover{ color: red !impo ...
- [转载]Java中继承、装饰者模式和代理模式的区别
[转载]Java中继承.装饰者模式和代理模式的区别 这是我在学Java Web时穿插学习Java设计模式的笔记 我就不转载原文了,直接指路好了: 装饰者模式和继承的区别: https://blog.c ...
随机推荐
- P1080 国王游戏
题意: 让n 位大臣排成一排,国王站在队伍的最前面. 排好队后,所有的大臣都会获得国王奖赏的若干金币, 每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向 ...
- USACO 1.1.1 YOUR RIDE IS HERE
众所周知,在每一个彗星后都有一只UFO.这些UFO时常来收集地球上的忠诚支持者.不幸的是,他们的飞碟每次出行都只能带上一组支持者.因此,他们要用一种聪明的方案让这些小组提前知道谁会被彗星带走.他们为每 ...
- NYOJ1238 最小换乘 (dijkstra)
最少换乘 时间限制:2000 ms | 内存限制:65535 KB 难度:3 描述 欧洲某城是一个著名的旅游胜地,每年都有成千上万的人前来观光旅行.Dr. Kong决定利用暑假好好游览一番.. ...
- Problem Arrangement ZOJ - 3777(状压dp + 期望)
ZOJ - 3777 就是一个入门状压dp期望 dp[i][j] 当前状态为i,分数为j时的情况数然后看代码 有注释 #include <iostream> #include <cs ...
- 利用zookeeper生成唯一id
package com.cxy.com.cxy.curator; import java.util.concurrent.ExecutorService; import java.util.concu ...
- 【2014年百度之星资格赛1001】Energy Conversion
Problem Description 魔法师百小度也有遇到难题的时候—— 现在,百小度正在一个古老的石门面前,石门上有一段古老的魔法文字,读懂这种魔法文字需要耗费大量的能量和大量的脑力. 过了许久, ...
- Vue 父页面 值传递 不到 子组件....
...各种百度无果..最后发现 这两个值 都是绑定的一个 ajax....... 坑爹啊..所以注意了....以后的写法.... 比如 data:{ data1: data2: } 假如 data1 ...
- Ueeidor 使用
setContent 要放在 ue.read(function(){ })中... js 字符串参数不要忘记 引号.....而且最好是单引号!!!
- The MathType DLL cannot be found 一劳永逸的方法
可能会看到下面的情况,然后实际上我们也能用过外部打开直接使用,那要你何用? 于是,我们找到这个文件,删除就OK 反正我写完论文就卸载了...
- Go语言基础之4--流程控制
一.if else语句 1.1 基本语法1 语法1: if condition { //do something } 语法2: if condition { //do something } else ...