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. luogu4088 [USACO18FEB]Slingshot

    link 这题在线得写树套树,所以我写的离线+树状数组 对于每个询问,Ans=\(\max_{j=1}^n{|a_j-x_i|+|b_j-y_i|+t_i}\) 拆成四种情况 \(x_i\le a_j ...

  2. [转载]sscanf函数

    来源:http://c.biancheng.net/cpp/html/296.html 头文件:#include <stdio.h> sscanf()函数用于从字符串中读取指定格式的数据, ...

  3. FlowLayout(流式布局)用法

    https://blog.csdn.net/liujun13579/article/details/7771191

  4. git学习---去除版本控制

    本地这样去除文件夹 node_modules 的版本关联:执行:git rm -r --cached "node_modules/"提交: git commit -am 'remo ...

  5. codeforces-984D——XOR-pyramid(DP)

    题目传送门 题目描述:给你一个f函数,这个函数的自变量是一个数列,函数表达式就是题目所给的描述,然后给你一个数列,问你数列中某区间  怎么选取 可以使函数值最大. 题目思路:  有关区间选取的问题,很 ...

  6. linux mysql下载地址

    linux mysql下载地址: https://dev.mysql.com/downloads/mysql/5.7.html#downloads

  7. phpstudy+phpstorm配置xdebug

    配置这个xdebug真的是一个很崎岖的过程.首先在网上搜了一下资料~说要下载xdebug对应的版本~然后打印phpinfo之类一堆~结果没有起作用~当时一直就觉得是不是版本不对.然后在群里面问别个给我 ...

  8. 6.SpringMVC2

    1.视图解析 当客户端发出请求后,交由SpringMVC的DispatcherServlet处理,接着Spring会分析看哪一个HandlerMapping定义的所有请求映射中对该请求的最合理的映射, ...

  9. python 和 C# DES加密

    C# code: using System; using System.IO; using System.Security.Cryptography; using System.Text; names ...

  10. js随机生成[n,m)的数字(不包括m)

    Math.random();//随机生成0到1的数字 Math.floor();//取小整 Math.floor(Math.random()*(最大值 - 最小值) + 最小值) 生成2到8的数:Ma ...