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. kali2017.2之***ss安装与使用

    一.命令行安装:apt-get install python-pip    ###安装pipsudo pip install shadowsocks    ###安装ssgedit /etc/shad ...

  2. ORA-01950:no privileges on tablespace 'USERS'

    ORA-01950:no privileges on tablespace 'USERS' SQL>create user myuser identitied by password; SQL& ...

  3. xlrd和xlwd模块

    xlrd模块 是python中一个第三方的用于读取excle表格的模块 exlce结构分析 一个excle表格包含多个sheet 一个sheet中包含多行多列 每个单元格具备唯一的行号和列号 常用函数 ...

  4. css属性 盒子模型

    一.    css属性相关 1.宽和高    1.width可以为元素设置宽度 2. height可以为元素设置高度 3.只有块级标签才可以设置宽度和高度,内联标签并不能设置宽度和高度,及时设置了也不 ...

  5. Realm数据库的使用

    https://github.com/lipanquan/Realm/tree/master

  6. Linux 防火墙iptables 实例

    iptables的基本语法格式 iptables [-t 表名] 命令选项 [链名] [条件匹配] [-j 目标动作或跳转] 说明:表名.链名用于指定iptables命令所操作的表和链,命令选项用于指 ...

  7. Photoshop入门教程(一):文本新建与概念解析

    写在开头 <Photoshop实用入门>系列教程可能对于一点都没有接触过Photoshop的人来说不太容易接受,因为本教程并没有细致到教你如何使用画笔工具等一系列很基础的东西,有些地方的讲 ...

  8. arraylist和linkedlist内部的实现大致是怎样的

    1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构. 2.对于随机访问get和set,ArrayList优于LinkedList,因为ArrayList可以随 ...

  9. Problem07 处理字符串

    题目:输入一行字符,分别统计出其中英文字母.空格.数字和其它字符的个数. 程序分析:利用while 语句,条件为输入的字符不为'\n'. import java.util.*; public clas ...

  10. thinkPHP 全局函数

    M函数 TP的Model父类,封装的功能比较多,增删改查操作都具备.一些表,比如留言表,comment class CommentModel extends Model { } M('comment' ...