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. linux中断和异常睡眠问题

    中断和异常: 中断只代表异步中断,异常代表同步中断,这样系统调用是异常处理,不是中断处理. 这里异常处理是可以休眠block的,因为异常处理所需的数据是存储在异常栈中,而每个进程都有一个异常栈,所以异 ...

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

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

  3. Qt 学习之路 2(10):对象模型

    Home / Qt 学习之路 2 / Qt 学习之路 2(10):对象模型 Qt 学习之路 2(10):对象模型  豆子  2012年9月2日  Qt 学习之路 2  45条评论 标准 C++ 对象模 ...

  4. Linux中切换前后台命令:ctrl+z,bg,fg,jobs

    一.运行某些服务的时候,我希望切换到后台运行: 两种方法: 1.可以在运行的时候,在启动服务命令的最后面加一个字符&,例如 ./serviceStart & 2.在服务启动后,按ctr ...

  5. CuteFTP文件列表按名称排序,有中文文件名时,软件死掉的解决办法

    看到很多人的解决办法是切换到一个没有中文的文件夹,点击排序后,再切换回来,这个的确是可以解决问题,但是有些繁琐! 直接一步到位的解决办法是: 依次点击菜单:工具->全局选项->导航-> ...

  6. python3 logging笔记

    #coding:utf-8import logging logger = logging.getLogger("simple_example")#可以说是日志信息的名字吧,可以随便 ...

  7. 3.Servlet(二)

    1.Servlet应用开发接口 对Servlet应用开发接口及功能的掌握,决定了是否能做好Servlet开发工作. GenericServlet抽象类 HttpServlet抽象类 2.Servlet ...

  8. idea(1)-idea初装

    1.安装插件 Alibaba Java Coding Guidelines Free Mybatis plugin MyBatis Log Plugin Lombok pluginGsonFormat ...

  9. JavaSE---值传递、引用传递

    1.概述 1.1 值传递:传递的是值的拷贝:引用传递:传递的是引用的地址值:(Java中统称为值传递) 1.2 java中只有   基本数据类型.String s="aa";这2种 ...

  10. python 层次索引交换级别以及排序问题