继承 多态 接口 抽象类 内部类
1.继承概述
class Student{
String name;
int age;
void study(){
System.out.println("study...");
}
}
class Worker{
String name;
int age;
void work(){
System.out.println("work...");
}
}
以上代码可以看到的是,多个事物之间有共同的属性或行为,这种代码的复用性比较差,怎么办?
可以将多个事物之间重复性的属性或行为进行抽取,抽取出来之后放在另外一个单独的类里面即可
class Student{
void study(){
System.out.println("study...");
}
}
class Worker{
void work(){
System.out.println("work...");
}
}
class Teacher{
void teach(){
System.out.println("teach...");
}
}
class Person{
String name;
int age;
}
虽然我们将Person类抽取出来,但是目前Worker和Student和Teacher与Person有关系吗?没有
那么如何让类之间产生父(Person)子(Worker Student Teacher)的关系?需要使用关键字extends
class Student extends Person{
void study(){
System.out.println("study...");
}
}
class Worker extends Person{
void work(){
System.out.println("work...");
}
}
class Teacher extends Person{
void teach(){
System.out.println("teach...");
}
}
class Person{
String name;
int age;
}
class Dog{
void kanmen(){}
}
总结:把多个事物中重复性的内容进行抽取,并生成另一个类,该类就是其他类的父类,其他类称之为子类,父类与子类之间用extends关键字来标明
继承的好处
- 继承的出现了提高了代码的复用性
- 继承的出现让类与类之间产生关系,也为我们后面的多态提供了前提
单继承与多继承
在现实生活中,父与子是一对多关系,子与父是一对一关系
使用继承时,除了要考虑类与类之间重复的内容之外,更重要的是去靠率关系,必须是一种 is a关系,即XXX是YYY的一种!苹果是水果的一种,狗是动物的一种
Java中,类与类之间只能支持单继承,接口与接口之间可以支持多继承
class Test extends Test1{}
class Test extends Test1,Test2{}//Error
继承体系
既然有了单继承,也有了父子关系,爷孙关系,曾祖父-重孙,继承出现了层级,继承体系
class A{}
class B extends A{}
class C extends A{}
class D extends C{}
......
继承使用需要注意的问题
- 继承和传统的理解稍微有一些不同,子类并不是父类的一个子集!实际上,一个子类通常要比它的父类包含更多的信息和方法。(子类更多的是父类的一种升级和延续)
- 父类中的一些私有内容,子类是获取不到的。如果父类对其自身的私有内容设置了公共的访问器和修改器的话,子类可以通过该访问器和修改器来获取父类的私有内容。
- 不要为了获取某一个特殊的属性或行为,而去乱认爸爸
- 总之,在设计类和其继承关系时,一定要符合社会常识认知
子父类中成员变量的特点
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
}
}
class Fu{
int num = 10;
}
class Zi extends Fu{
}
如果子类没有,父类有且非私有,子类对象可以获取num
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
}
}
class Fu{
private int num = 10;
}
class Zi extends Fu{
}
子类没有,父类有且私有,子类对象不能获取num
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
}
}
class Fu{
//int num = 10;
}
class Zi extends Fu{
int num = 20;
}
子类有,父类有且非私有或是没有,子类对象获取的是子类的num
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
zi.Show();
}
}
//父类 超类 基类
class Fu{
int num = 10;
}
class Zi extends Fu{
int num = 20;
void Show(){
int num = 30;
System.out.println(num + "," + this.num + "," + super.num);
}
}
如果子类中,成员变量和父类变量和局部变量重名时 ,以上代码可以解决。有一个特殊的super
- this表示的是当前对象,存的是当前对象在堆内存中的地址
- super不表示父类的对象,因为在此我们并没有去创建父类的对象。super仅仅表示父类的空间,并没有创建父类对象
函数的重写
在子父类中,同名函数
- 保留父类的功能声明 子类进一步优化
- 保留父类的功能声明 子类可以重写定义
重写当中应该注意到的一些细节:
- 函数重名,但是参数列表不同,不构成重写关系
- 函数重名,参数列表相同,构成重写关系,返回值类型也必须是一样的
- 子类重写父类函数时,权限>=父类权限
- 如果父类函数权限为private 子类压根没有继承到
子父类中构造函数的特点
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
//父类 超类 基类
class Fu{
Fu(){
System.out.println("Fu show...");
}
}
class Zi extends Fu{
Zi(){
System.out.println("Zi show...");
}
}
可以看到的是当创建子类对象时,在子类的构造函数执行之前,父类的构造函数先执行,虽然父类的构造函数执行,但不代表父类对象的创建
- 每一个类中的构造函数第一句如果不是
this()
调用本类中其他构造函数的话,默认第一句是隐藏的super()
- 是因为在创建子类对象的时候,需要为父类继承给子类的一些数据进行初始化
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
class Fu{
int num;
Fu(){
System.out.println("Fu show..." + num);
num = 4;
}
}
class Zi extends Fu{
Zi(){
super();//调用父类的无参构造函数 默认隐藏
//父类的构造函数一旦执行完毕 则紧接着执行子类成员显示初始化
System.out.println("Zi show..." + num);
}
}
this()与super()是否冲突
public class Test {
public static void main(String[] args) {
Zi zi1 = new Zi();
Zi zi2 = new Zi(1);
Zi zi3 = new Zi(1,2);
}
}
class Fu{
int num;
Fu(){
System.out.println("Fu show...");
num = 4;
}
}
class Zi extends Fu{
Zi(){
System.out.println("Zi show...0");
}
Zi(int a){
System.out.println("Zi show...1");
}
Zi(int a,int b){
System.out.println("Zi show...2");
}
}
如果子类的构造函数之间没有调用关系,则每一个构造函数的第一句都是super()
public class Test {
public static void main(String[] args) {
Zi zi1 = new Zi();
Zi zi2 = new Zi(1);
Zi zi3 = new Zi(1,2);
}
}
class Fu{
int num;
Fu(){
System.out.println("Fu show...");
}
}
class Zi extends Fu{
Zi(){
this(1);
System.out.println("Zi show...0");
}
Zi(int a){
this(1,2);
System.out.println("Zi show...1");
}
Zi(int a,int b){
super();
System.out.println("Zi show...2");
}
}
在上一段代码中,Fu show的执行,在每一个构造函数中的第一句super()执行
在这一段代码中,Fu show的执行,在Zi(int,int)调用执行的
在构造函数中,第一句要么是this(),要么是super()
有没有可能每一个构造函数的第一句都是this()?没有,否则递归调用
有没有可能每一个构造函数的第一句都是super()? 有,构造函数之前不调用
this()与super()本身不冲突,如果构造函之间有调用关系,那么最后一个被调用的函数不能回调,那么其第一句就不能是this(),只能是super()
public class Test {
public static void main(String[] args) {
Zi zi1 = new Zi();
Zi zi2 = new Zi(1);
Zi zi3 = new Zi(1,2);
}
}
class Fu{
int num;
Fu(int a){
System.out.println("Fu show...");
}
}
class Zi extends Fu{
Zi(){
this(1);
System.out.println("Zi show...0");
}
Zi(int a){
this(1,2);
System.out.println("Zi show...1");
}
Zi(int a,int b){
super(a);
System.out.println("Zi show...2");
}
}
如果父类中没有无参构造函数存在,只有有参数的构造函数的话,那么子类中默认的super()
就调用不到父类无参构造函数,引发错误!
建议每一个类都把它的 无参构造函数 写出来
public class Test {
public static void main(String[] args) {
Zi zi1 = new Zi();
Zi zi2 = new Zi(3);
Zi zi3 = new Zi(5,6);
}
}
class Fu{
int num;
Fu(){
System.out.println("Fu constructor...0 " + "num=" + num);
num = 10;
}
Fu(int a){
System.out.println("Fu constructor...1 " + "num=" + num);
num = a;
}
}
class Zi extends Fu{
int num = 20;
Zi(){
System.out.println("Zi constructor...0 " + "num=" +num + " fu num=" + super.num);
}
Zi(int a){
this(a,0);
System.out.println("Zi constructor...1 " + "num=" +num + " fu num=" + super.num);
}
Zi(int a,int b){
super(a+b);
num = a +b;
System.out.println("Zi constructor...2 " + "num=" +num + " fu num=" + super.num);
}
}
2.final关键字
final翻译过来是最终,final可以修饰变量、函数、类
final修饰变量
表示该变量的值不可被改变
变量主要分为,基本数据类型变量,引用数据类型变量
- 如果final修饰基本数据类型变量,表示变量所存储的常量值不能改变
- 如果final修饰引用数据类型变量,表示变量所存的对象地址值不能改变 但是可以改变对象中的数据(如果对象中的数据也是final则也不能修改)
public class Test {
public static void main(String[] args) {
Demo d = new Demo();
System.out.println(d.num);
/* d.num = 5;
Error:(7, 10) java: 无法为最终变量num分配值*/
final int[] arr =new int[]{1,2,3};
/*arr = new int[]{4,5,6};
Error:(10, 9) java: 无法为最终变量arr分配值*/
arr[1] = 10;
for (int i = 0; i < arr.length;i++){
System.out.print(arr[i] + ",");
}
}
}
class Demo{
//当前这个变量的值不能被修改
public final int num = 10;
}
public class Test {
public static void main(String[] args) {
final Demo d = new Demo();
/* d = new Demo();
Error:(6, 8) java: 无法为最终变量d分配值*/
/* d.num = 30;
Error:(8, 10) java: 无法为最终变量num分配值*/
}
}
class Demo{
public final int num = 10;
public int haha = 20;
}
一般而言,当我们在定义常量(字面量 用变量+final来表示),定义成静态变量
public static final 数据类型 变量名 = 常量数据;
对于常量的变量名起名规则为 全部单词大写 单词与单词之间用下划线分隔
public static final double PI = 3.14;
public static final int MAX_VALUE = 100;
final修饰函数
如果某一个类中的函数,不想让其子类去重写的话,该函数就可以声明为final类型
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
class Fu{
final void show(){
System.out.println("可以继承到show");
}
}
class Zi extends Fu{
/*void show(){}
Error:(12, 10) java: com.company.Zi中的show()无法覆盖com.company.Fu中的show()
被覆盖的方法为final*/
}
Zi类确实继承到了show(),也可以调用该函数,但是由于show是final,所以子类不能重写父类的show函数
final修饰类
表示该类不能被继承
public class Test {
public static void main(String[] args) {
}
}
final class Fu{
}
/*class Zi extends Fu{
Error:(10, 18) java: 无法从最终com.company.Fu进行继承
}*/
3.抽象类
抽象:指的就是不具体,模糊不清这种含义
不能直接将抽象和类进行挂钩,之所以有抽象类的存在,是因为有抽象函数
具有抽象函数的类,称之为抽象类
抽象函数
public class Test {
public static void main(String[] args) {
Dog d = new Dog();
d.jiao();
d.eat();
Cat c = new Cat();
c.jiao();
c.eat();
/* Anmial a = new Anmial();
Error:(11, 20) java: Anmial是抽象的; 无法实例化*/
}
}
abstract class Anmial{
abstract void jiao();
abstract void eat();
}
class Dog extends Anmial{
@Override
void jiao(){
System.out.println("汪汪汪");
}
void kanmen(){
System.out.println("看门");
}
@Override
void eat(){
System.out.println("狗吃骨头");
}
}
class Cat extends Anmial{
@Override
void jiao(){
System.out.println("喵喵喵");
}
void catMouse(){
System.out.println("猫捉老鼠");
}
@Override
void eat(){
System.out.println("猫吃鱼");
}
}
/*
class Pig extends Anmial{
void gongbaicai(){
System.out.println("猪拱白菜");
}
}
Error:(45, 1) java: Pig不是抽象的, 并且未覆盖Anmial中的抽象方法eat()*/
抽象函数:当我们将多个事物的共同行为(函数)进行抽取并封装到另外一个类中时,发现在该类中,这些方法的具体执行内容无法确定,只能有这些子类来决定该函数的具体执行,那么在该类中,将这些抽取来的函数仅函数保留函数声明,不保留函数体即可,那么该函数就是抽象函数,用abstract关键字来修饰,既然有了抽象函数的存在,那么具有抽象函数的类也被成为抽象类,也必须用abstract修饰。抽象类不能创建对象,只有其实现子类能够创建对象
/*
class Pig extends Anmial{
void gongbaicai(){
System.out.println("猪拱白菜");
}
}
Error:(45, 1) java: Pig不是抽象的, 并且未覆盖Anmial中的抽象方法eat()*/
此处的Pig虽然是Anima的子类,但是并未重写/覆盖/实现Animal中的抽象函数,所以报错
如何解决?要么把Pig声明为抽象类,要么Pig重写抽象函数
抽象类的特点
- 抽象类和抽象函数都需要被abstract修饰,抽象方法一定在抽象类中
- 抽象类不能创建对象,因为如果一旦创建对象,在调用其函数时,函数没有具体的执行内容
- 只有覆盖了抽象类中所有的抽象函数后,子类才可以实例化,否则该子类还是一个抽象类
关于抽象类的细节问题
- 抽象类一定是一个父类吗?
是的,因为抽象类本身就是由多个事物进行抽取而来的
- 抽象类是否有成员变量,成员函数,构造函数呢?
有,抽象类与一般类唯一的区别就是抽象类中有抽象函数,其他相同(抽象类不能创建对象)
- 抽象类和一般类的异同点
相同点
- 它们都是用来描述事物的
- 它们之中都可以去定义属性和行为
不同点
- 一般类可以具体的描述事物,抽象类描述事物时会有一些不具体的信息
- 抽象类比一般类可以多定义一个成员:抽象函数
- 一般类可以创建对象,抽象类不能创建对象
- 抽象类中是否可以不定义抽象函数?
可以的。有抽象函数的类一定时抽象类,抽象类不一定有抽象函数
- 抽象关键字abstract不能与哪些其他关键字共存
- final:final如果修饰类,表示该类不能被继承,final修饰函数时,表示函数不能被重写;不能,抽象类本身就是父类,并且其中的抽象函数就等着被子类重写。
- private:private修饰函数,表示函数被私有,不能被子类继承;不能,抽象函数就等着被子类重写
- static:static修饰的函数,属于类的,随着类的加载,从而被加载进方法去,和对象没有关系了,可以直接用类调用静态成员,如果抽象函数被static修饰,被类调用没有意义。
综合案例:线性表
public class Test {
public static void main(String[] args){
LinkedList l = new LinkedList();
l.add(0,1);
System.out.println(l.get(0));
}
}
//定义一个线性表List类 声明了该线性表的共同操作
abstract class List{
//在指定角标index处添加元素e
public abstract void add(int index,int e);
//删除执行角标index出的元素,并返回该元素值
public abstract int delete(int index);
public abstract int get(int index);
//修改指定角标处index的元素为新元素e,并返回原先的值
public abstract int set(int index,int e);
//返回线性表中有效元素的个数
public abstract int size();
//清空线性表
public abstract void clear();
//判断线性表是否为空
public abstract boolean isEmpty();
}
//链表的结点
class Node{
int data;//数据域
Node next;//指针域
public Node(){
}
public Node(int data){
this.data = data;
}
public Node(int data,Node next){
this.data = data;
this.next = next;
}
public String toString(){
return "(" + data + ")";
}
}
//基于链表实现线性表,链式存储
class LinkedList extends List{
private Node head;
private int size;
public LinkedList(){
head = new Node();
}
@Override
//在指定角标index处添加元素e
public void add(int index, int e) {
if(index < 0 || index > size){
throw new IllegalArgumentException("add() index out of range");//异常
}
Node pre = getNode(index - 1);
Node n = new Node(e);
pre.next = n.next;
pre.next = n;
size++;
}
@Override
//删除执行角标index出的元素,并返回该元素值
public int delete(int index) {
if(index < 0 || index >= size){
throw new IllegalArgumentException("get() index out of range");//异常
}
Node pre = getNode(index - 1);
Node p = getNode(index);
pre.next = p.next;
p.next = null;
size--;
return p.data;
}
@Override
public int get(int index) {
if(index < 0 || index >= size){
throw new IllegalArgumentException("get() index out of range");//异常
}
return getNode(index).data;
}
//返回指定角标index处的结点对象
private Node getNode(int index){
Node p = head;
for(int i = 0;i <= index;i++){
p = p.next;
}
return p;
}
@Override
//修改指定角标处index的元素为新元素e,并返回原先的值
public int set(int index,int e) {
if(index < 0 || index >= size){
throw new IllegalArgumentException("set() index out of range");//异常
}
Node p = getNode(index);
int ret = p.data;
p.data = e;
return ret;
}
@Override
//返回线性表中有效元素的个数
public int size() {
return size;
}
@Override
//清空线性表
public void clear() {
head.next = null;
size = 0;
}
@Override
//判断线性表是否为空
public boolean isEmpty() {
return size == 0 && head.next == null;
}
}
4.接口
从代码的角度上而言,接口其实就是抽象类的一种特殊表现形式
当一个抽象类中,所有的方法都是抽象函数时,那么,该类就可以用接口来表示
接口还是类吗?不是,一些类的功能和操作不再适用于接口
接口中没有成员函数,没有成员变量,没有构造函数,没有静态函数,没有静态变量
接口也不能直接去创建对象
interface List{
public abstract void add(int index,int e);
public abstract int delete(int index);
public abstract int get(int index);
public abstract int set(int index,int e);
public abstract int size();
public abstract void clear();
public abstract boolean isEmpty();
}
接口中的变量和函数就会有一些特殊的含义
- 接口中的变量 默认是公共静态常量 public static final 类型 就算不写这些关键字 也是默认的
- 接口中的函数 默认是公共抽象函数 public abstract类型 就算不写这些关键字 也是默认的
interface InterfaceA{
int num = 0;
//这里面num已经不是成员变量的含义 默认是 public static final类型
void show();
//默认是public abstract类型
}
接口和类之间的关系
类与类之间是单继承关系,类与接口之间是多实现关系,接口与接口之间是多继承关系
类与接口之间的实现关系用imlpements关键字表示
- 要么这个类实现接口中所有的方法
- 要么这个类声明为abstract,这一点和继承抽象类一致
interface InterfaceA{
void showA();
}
//叫做DemoA类实现了InterfaceA这个接口
/*class DemoA implements InterfaceA{
@Override
public void showA(){
System.out.println("DemoA showA");
}
}*/
abstract class DemoA implements InterfaceA{
}
类与接口有着多实现的存在,要么把这几个接口全部实现,要么声明为abstract
interface InterfaceA{
void showA();
}
interface InterfaceB{
void showB();
}
class DemoB implements InterfaceA,InterfaceB{
@Override
public void showA(){}
@Override
public void showB(){}
}
接口与接口有多继承关系,对于InterfaceC接口的实现子类而言,要么把这几个接口全部实现,要么声明为abstract
interface InterfaceA{
void showA();
}
interface InterfaceB{
void showB();
}
interface InterfaceC extends InterfaceA,InterfaceB{
void showC();
}
class DemoC implements InterfaceC{
@Override
public void showA() {}
@Override
public void showB() {}
@Override
public void showC() {}
}
接口与接口之间不会存在实现关系。
接口中的特点
- 接口中的变量都是全局静态常量
- 接口中的方法都是全局抽象函数
- 接口不可以创建对象
- 子类必须覆盖接口中的所以抽象方法,或声明为abstract
- 类与接口之间可以存在多实现关系
- 接口与接口之间可以多继承关系
- 类与类之间只能是单继承关系
接口的存在,主要解决的就是类与类之间只有单继承的关系
类在继承的同时也可以进行接口的实现
class DemoA{
void ShowA(){}
}
interface DemoB{
void ShowB();
}
//如果DemoC既有DemoA的描述 又有DemoB的描述
//也就是意味着DemoC可能要有两个父类 Java机制中不允许多父类的存在
class DemoC extends DemoA interface DemoB{
public void showA(){}
public void showB(){}
}
当一个类在继承另外一个类的时候,就已经用有了该继承体系的所有功能,接口的作用就是在这些体系功能之上,增加的一些额外的功能 !大大的扩展了类的功能!
接口除了作为类的功能扩展之外,接口还可以作为一种对外暴露的规则,来进行解耦操作
public class Test {
public static void main(String[] args){
Computer computer = new Computer();
Mouse mouse = new Mouse();
KeyBoard keyBoard = new KeyBoard();
Creame creame = new Creame();
computer.getDev1(mouse);
computer.getDev2(keyBoard);
computer.getDev3(creame);
}
}
interface USB{
void getContent();
}
class Computer{
//获取USB接口的设备1
public void getDev1(USB dev){//USB dev = new Mouse();
System.out.println("电脑连接了设备1");
dev.getContent();
}
//获取USB接口的设备2
public void getDev2(USB dev){
System.out.println("电脑连接了设备2");
dev.getContent();
}
//获取USB接口的设备3
public void getDev3(USB dev){
System.out.println("电脑连接了设备3");
dev.getContent();
}
}
class Mouse implements USB{
public void getContent(){
System.out.println("鼠标已经连接电脑,开始运行");
}
}
class KeyBoard implements USB{
public void getContent(){
System.out.println("键盘已经连接电脑,开始运行");
}
}
class Creame implements USB{
public void getContent(){
System.out.println("相机已经连接电脑,开始运行");
}
}
接口之间可以多继承,类之间不能多继承
public class Test {
public static void main(String[] args){
Demo d = new Demo();
d.show();
}
}
interface InterfaceA{
void show();//妈妈希望你过得好
}
interface InterfaceB{
void show();//爸爸希望你过得好
}
interface InterfaceC extends InterfaceA,InterfaceB{
}
class Demo implements InterfaceC{
@Override
public void show() {//自己过得好不好 自己决定
System.out.println("showc...");
}
}
public class Test {
public static void main(String[] args){
/* DemoC dc = new DemoC();
dc.show();//产生调用的二义性 因为两个父类中的函数都有函数体 不知道执行哪个*/
}
}
/*
class DemoA{
void show(){//妈妈希望你成才 成为医生
System.out.println("Kill DemoB");
}
}
class DemoB{
void show(){//爸爸希望你成才 成为教师
System.out.println("Kill DemoA");
}
}
class DemoC extends DemoA,DemoB{
//成才 成啥 不知道 有二义性
}*/
归根结底,看函数的函数体
接口与抽象类的区别
相同点:
- 都位于继承或实现的顶端
- 都不能实例化
- 都包含抽象函数,其子类都必须覆盖这些方法
不同点:
- 一个类只能继承一个父类,但是可以实现多个接口
- 抽象类中其实可以存在一些已经实现好的方法,有部分未实现的方法由子类决定;接口中只能包含抽象函数,子类必须完全实现
5.多态
多种状态:就是指一个对象可以有多种状态(当前对象在继承体系中的位置变化)
位置的变化,只能是向上变 但不能低于自身
不同的视角,不同的角色,无论在哪个视角,对象本身变了没有?只不过我们需要对象在不同的场合表现出相对应的行为
多态的代码表现
父类的引用指向子类的对象
public class Test {
public static void main(String[] args){
Son s = new Son();
Dady d = new Son();//父类的引用指向子类的对象
d.chouyan();
d.hejiu();
d.tangtou();
}
}
class Dady{
void chouyan(){
System.out.println("抽烟");
}
void hejiu(){
System.out.println("喝酒");
}
void tangtou(){
System.out.println("烫头");
}
}
class Son extends Dady{
@Override
void chouyan() {
System.out.println("儿子抽烟");
}
@Override
void hejiu(){
System.out.println("儿子喝酒");
}
@Override
void tangtou(){
System.out.println("儿子烫头");
}
void lol(){
System.out.println("儿子玩lol");
}
}
多态的前提:继承 重写
多态的好处:对代码的功能进行了可扩展性
子类对象可以当作父类对象去使用 但是有限制,只能调用父类函数或者重写的函数,不能使用子类特有的行为
多态当中的特点:
- 多态当中成员变量的特点,只能访问父类中的成员变量
- 多态当中成员函数的特点
- 如果子类没有重写 且父类中有 调用父类
- 如果子类有重写 调用子类重写的
- 如果不存在重写 父类没有 那就报错
public class Test {
public static void main(String[] args) {
Dog d = new Dog();
Cat c = new Cat();
Pig p = new Pig();
feed(d);
feed(c);
feed(p);
}
//Animal a = new Dog();
//Animal a = new Cat();向上转型(向上类型转换)
public static void feed(Anmial a){
a.eat();
/*
//ClassCastException 类型转换异常
Pig pp = (Pig)a;
pp.gongbaicai();*/
//判断对象的本质类型 instanof
if(a instanceof Pig){
Pig pp = (Pig)a;
pp.gongbaicai();
}
}
}
class Anmial{
void jiao(){}
void eat(){}
}
class Dog extends Anmial{
@Override
void jiao(){
System.out.println("汪汪汪");
}
@Override
void eat(){
System.out.println("狗吃骨头");
}
void kanmen(){
System.out.println("看门");
}
}
class Cat extends Anmial{
@Override
void jiao(){
System.out.println("喵喵喵");
}
@Override
void eat(){
System.out.println("猫吃鱼");
}
void catMouse(){
System.out.println("猫捉老鼠");
}
}
class Pig extends Anmial{
@Override
void jiao(){
System.out.println("哼哼哼");
}
@Override
void eat(){
System.out.println("猪啥都吃");
}
void gongbaicai(){
System.out.println("猪拱白菜");
}
}
6.内部类
就是当我们在描述一个事物的时候,发现该事物当中又存在另一个事物的时候
我们把当前的事物成为外部类,另一个事物称之为内部类
如何调用内部类的成员
想要调用内部类的成员,必须先创建内部类的对象new Inner()
但是直接new Inner()发现找不到Inner这个类
因为Inner是Outter的非静态成员
所以Inner这个类想过要存在的前提是创建Outter对象
public class Test {
public static void main(String[] args) {
Outtter.Inner inner = new Outtter().new Inner();
System.out.println(inner.num);
inner.show();
}
}
class Outtter{
int num = 10;
void show(){
System.out.println("Outter show...");
}
class Inner{
int num = 20;
void show(){
System.out.println("Inner show...");
}
}
}
如何区分内部类成员和外部类成员
public class Test {
public static void main(String[] args) {
Outtter.Inner inner = new Outtter().new Inner();
System.out.println(inner.num);
inner.show();
}
}
class Outtter{
int num = 10;
void show(){
System.out.println("Outter show...");
}
class Inner{
int num = 20;
void show(){
System.out.println("Inner show...");
//Outter.this.num
//Outter.(这个类的)this.(的对象)num(的num)
System.out.println(Outtter.this.num + "," + this.num);
}
}
}
如何调用内部类的静态成员
静态的东西是优先加载进方法区的,然而haha在一个非静态的类当中,必须先创建Inner对象
不到Inner这个类
因为Inner是Outter的非静态成员
所以Inner这个类想过要存在的前提是创建Outter对象
public class Test {
public static void main(String[] args) {
Outtter.Inner inner = new Outtter().new Inner();
System.out.println(inner.num);
inner.show();
}
}
class Outtter{
int num = 10;
void show(){
System.out.println("Outter show...");
}
class Inner{
int num = 20;
void show(){
System.out.println("Inner show...");
}
}
}
如何区分内部类成员和外部类成员
public class Test {
public static void main(String[] args) {
Outtter.Inner inner = new Outtter().new Inner();
System.out.println(inner.num);
inner.show();
}
}
class Outtter{
int num = 10;
void show(){
System.out.println("Outter show...");
}
class Inner{
int num = 20;
void show(){
System.out.println("Inner show...");
//Outter.this.num
//Outter.(这个类的)this.(的对象)num(的num)
System.out.println(Outtter.this.num + "," + this.num);
}
}
}
如何调用内部类的静态成员
静态的东西是优先加载进方法区的,然而haha在一个非静态的类当中,必须先创建Inner对象
如果内部类中有静态 那么内部类必须是静态的,此时内部类当中无法访问外部类的非静态,但是可以访问内部类中的非静态