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;
}

一、作用

1)复用类

二、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 限制的属性和方法

3)子类要重写父类中的方法时,子类中重写的方法的访问控制权限必须要高于父类的方法的访问控制权限

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笔记 —— 继承的更多相关文章

  1. Java笔记: 继承成员覆盖和隐藏

    在扩展类时,既可以向类中添加新的成员,也可以重新定义现有的成员.重定义现有成员的具体效果取决于成员的类型.本文不会详细的介绍概念,只简要总结覆盖(overriding,也叫重写)和隐藏(hiding) ...

  2. [Java笔记]继承

    继承只是继承框架,而数据没有继承!. 继承不改变父类数据!

  3. java学习笔记 --- 继承

    继承 (1)定义:把多个类中相同的成员给提取出来定义到一个独立的类中.然后让这多个类和该独立的类产生一个关系,    这多个类就具备了这些内容.这个关系叫继承.  (2)Java中如何表示继承呢?格式 ...

  4. Java学习笔记二十三:Java的继承初始化顺序

    Java的继承初始化顺序 当使用继承这个特性时,程序是如何执行的: 继承的初始化顺序 1.初始化父类再初始子类 2.先执行初始化对象中属性,再执行构造方法中的初始化 当使用继承这个特性时,程序是如何执 ...

  5. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  6. java笔记整理

    Java 笔记整理 包含内容     Unix Java 基础, 数据库(Oracle jdbc Hibernate pl/sql), web, JSP, Struts, Ajax Spring, E ...

  7. Java笔记 —— 方法重载和方法重写

    Java笔记 -- 方法重载和方法重写 h2{ color: #4ABCDE; } a{ text-decoration: none !important; } a:hover{ color: red ...

  8. Java笔记 —— 初始化

    Java笔记 -- 初始化 h2{ color: #4ABCDE; } a{ text-decoration: none !important; } a:hover{ color: red !impo ...

  9. [转载]Java中继承、装饰者模式和代理模式的区别

    [转载]Java中继承.装饰者模式和代理模式的区别 这是我在学Java Web时穿插学习Java设计模式的笔记 我就不转载原文了,直接指路好了: 装饰者模式和继承的区别: https://blog.c ...

随机推荐

  1. jdk 1.6.0_43 下载

    Java SE Development Kit 6u43 Product / File Description File Size Download password Linux x86 65.43 ...

  2. const常量,常量折叠,字面常量

    const int a=10: 涉及到一个叫常量折叠的概念(认为我这说得太简单或者不好理解的可以google一下它获取更多信息), 即编译器虽然会给a分配空间(如果取a的地址进行操作的时候,会强迫编译 ...

  3. kuangbin专题七 HDU1754 I Hate It (单点修改维护最大值)

    很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有 ...

  4. [USACO19FEB]Moorio Kart(DP)

    Luogu5243 题解 即O(N^2)暴力统计出每个森林的路径,从ctgn个集合中各选出一个数,使得长度>=Y的方案数. 用背包统计.具体实现: \(dp[i+j][0]\leftarrow ...

  5. poj1125传播谣言(弗洛伊德,求最长路)

    Stockbroker Grapevine Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 38541   Accepted: ...

  6. 江西财经大学第一届程序设计竞赛 B

    链接:https://www.nowcoder.com/acm/contest/115/B来源:牛客网 题目描述 给出一个出生日期,比如:1999-09-09, 问:从出生那一天开始起,到今天2018 ...

  7. TP框架中D方法和M方法

    D()和M()方法的区别: D和M的区别主要在于 M方法不需要创建模型类文件,M方法不会读取模型类,所以默认情况下自动验证是无效的,但是可以通过动态赋值的方式实现 而D方法必须有创建模型类. 我们可以 ...

  8. python 函数调用

    ##########定义函数######### 如果不主动调用函数,函数是不会执行的 def say_hello():     print 'hello1'     print 'hello2'    ...

  9. 12.标准标签库(JSTL)

    1.JSTL标签库安装 JSTL的概念: JSP标准标签库(JSP Standard Tag Library)是一个实现 Web 应用程序中常见的通用功能的定制标记库集功能包括迭代和条件判断.数据管理 ...

  10. Spring实现AOP

    转载: https://blog.csdn.net/tolcf/article/details/49133119 [框架][Spring]XML配置实现AOP拦截-切点:JdkRegexpMethod ...