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 ...
随机推荐
- 10.11cdy考试题
鸣谢cdy math [题目描述] 众所周知, xkj是GH的得意门生, 可是xkj的数学成绩并不是很理想: 每次GH在批评完数学限训做的差的人时, 总会在后面加一句:咱们班还有一位做的最差的同学-- ...
- Codeforces Round #521 (Div. 3) C. Good Array
C. Good Array time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- Problem Arrangement ZOJ - 3777(状压dp + 期望)
ZOJ - 3777 就是一个入门状压dp期望 dp[i][j] 当前状态为i,分数为j时的情况数然后看代码 有注释 #include <iostream> #include <cs ...
- 奇妙的 CSS几何图形
三角形:通常会使用透明的border模拟出一个三角形:▲ .traingle { width:; height:; border-left: 50px solid transparent; borde ...
- appium ios 真机自动化环境搭建
近期由于工作需要,本小菜在弄appium+ios+iphone真机的移动自动化,在网上找寻各种资料,发现针对IOS方面的资料少之又少,公司其它部门的弄过的同事也寥寥无几,即使有,也是安卓方面的.本次书 ...
- select随笔
粘贴下面代码 select 美化 <!doctype html> <html lang="en"> <head> <meta charse ...
- github 0 学习
Github 快速上手实战教程 一.实验介绍 1.1 实验内容 本次课程讲的是在实验楼的在线环境中,如何使用 Github 去管理在在线环境中使用的代码.配置.资源等实验相关文件,怎样去添加.同步和下 ...
- plSql添加快捷键设置
汉化版:工具-首选项-用户界面-编辑器-自动替换-定义文件 英文版:Tools->Perferences->Editor中Autoreplaces选择配置的shortcuts 常用快捷键设 ...
- Android NDK开发 JNI类型签名和方法签名(六)
在Java存在两种数据类型: 基本类型 和 引用类型 ,大家都懂的 . 在JNI的世界里也存在类似的数据类型,与Java比较起来,其范围更具严格性,如下: 1.primitive types ---- ...
- RTT学习
一互斥量:是信号量的一种,用于共享资源的排他性使用,以锁的形式存在,初始化时为可用,不能在中断中使用,可能导致优先级翻转. 二 事件:创建.删除.初始化.解绑.等待.发送.可以一对多多对的,发送一个事 ...