从零学习Java之旅 Part2 面向对象部分

从零学习Java之旅 Part2 面向对象部分

类和对象基本概念

对象:java程序运行的基本单位,类似于组成客观世界中个体
对象包含两方面的内容:

  • 属性 用成员变量表示
  • 行为 用成员方法表示

类:类是所有对象共性的抽象

  • 属性:描述对象中有哪些属性(通过定义成员变量)
  • 行为:描述对象有哪些行为,以及行为的具体表现(通过定义成员方法)

类和对象的关系:类是用来描述对象的(描述对象有哪些属性、描述对象有哪些行为)。

对象和对象的关系:

  • 不同类的对象:具有不同的属性和行为
  • 同种类型的对象:对象有相同的属性,但是属性的取值可以各不相同
public class Demo1 {
    
    
	public static void main(String[] args) {
    
    
		int a = 10;
		int b = 20;
        Add add = new Add(a, b);
        System.out.println(add.sum());
	}
}
//创建Add类
class Add {
    
    
	//对象属性
	int m;
	int n;
	
	//默认无参构造方法,一旦自行创建构造方法,该方法就被覆盖了
	//public Add() { };
	//创建构造方法
	public Add(int a, int b) {
    
    
		m = a;
		n = b;
	}
	//对象行为
	public int sum() {
    
    
		return m + n;
	}
}

对象的创建及使用

  1. 创建对象,首先要定义类,描述对象有哪些属性和行为
  2. 定义好类之后,就可以使用new关键字,创建该类的对象
  3. 对象的使用,即访问对象的成员,通过**对象名. **的形式,后面接成员变量(属性)、成员方法(行为)。

从数据类型角度理解类和对象

  • 类:定义了一组数据集合(成员变量)和基于这个数据集合的一组操作(成员方法)
    是一种自定义类型。
  • 对象:自定义数据类型的一个"变量"。

类的加载
一个类,在一个jvm中,只会被最多加载一次。当首次创建一个类的对象的时候,才会触发该类的加载。(重要)
类和对象的内存映象

  • 类信息存储在方法区中,并且包含了每个方法实现的字节码指令。
  • 对象存储在堆上,对象中只存储了成员变量的值。

一个Java文件中可以定义多个类,但是一个Java文件中只能定义一个被public修饰的类,被public修饰的类,其类名必须和Java文件的文件名相同。

成员变量 VS 局部变量

  • 定义的位置不同:成员变量定义在方法体之外,局部变量定义在类体中或者是方法的形式参数。
  • 内存位置不同:成员变量的值存储在堆上,局部变量的值在栈上。
  • 生命周期不同:成员变量的存储空间随对象的销毁而销毁,局部变量随方法栈帧的销毁而销毁。
  • 初始值不同::局部变量没有被自动赋予默认初值,而成员变量会有默认初值。

方法引用类型的形式参数

实参和形参的值传递方式,是复制传递。
引用类型的变量,在调用方法和被调用方法中,都属于各自方法中定义的局部变量。
引用类型的实参和形参的值,在调用方法和被调用方法中各自都有一份。但是,引用类型的实参和形参所指向的数据,是同一份数据。

构造方法

作用:在创建对象的时候,完成对象成员变量的初始化工作。

如何完成对象成员变量初始化?
1.构造方法,可以接收参数,可以利用接受到的参数值,来初始化对象成员变量的初始值
2.在构造方法的方法体中,我们自己通过赋值语句,来完成对对象的赋值

class Example {
	int a;
	public Example(int b) {
	a = b;
	}
}
语法:方法名固定,必须和类名相同(所以构造方法的名字违反了驼峰命名规则,这是Java语言规定的)。
方法声明中,没有返回值类型这一项。
其他和普通的方法定义类似

注意事项:

  • 构造方法可以重载:重载条件和普通方法的重载条件相同,可以根据new 类名(实参列表)中的实参列表指明创建某对象时所使用的构造方法。
  • 如果没有定义任何构造方法,则jvm会自动帮我们添加一个默认无参构造方法,否则,不会。
  • 构造方法的执行时机: 在创建对象的最后一步才会执行,jvm用来初始化对象中成员变量的值。
  • 如果想开辟内存空间,只能依靠关键字new来进行开辟。即:只要看到关键字new不管何种情况下,都表示要开辟新的内存空间。

特殊语法

this

this:表示当前对象自身的引用

如何确定this指的是哪个对象?

  • 如果this出现在构造方法中,指的是正在创建的那个对象
  • 如果this出现在成员方法中,因为成员方法总是以对象名. 的方式访问,使用哪个对象访问该方法,this就指的是那个对象。
public class Demo1 {
    
    
	public static void main(String[] args) {
    
    
		int a = 10;
		int b = 20;
        Add n = new Add(a, b);
        n.printSum;
	}
}
//创建Add类
class Add {
    
    
	//对象属性
	int a;
	int b;
	
	//默认无参构造方法,一旦自行创建构造方法,该方法就被覆盖了
	//public Add() { };
	public Add(int a, int b) {
    
    
		this.a = a;
		this.b = b;
	}
	//对象行为
	public void printSum() {
    
    
		System.out.println(this.a + this.b);
	}
}

调用构造方法的this只能出现在构造方法中,且只能在第一行。普通成员方法的方法体中,不能利用this调用。
同名变量要加this来区分。

this的作用:
1、解决成员变量的隐藏问题
2、访问对象的成员变量和成员方法
3、访问对象的构造方法,this(参数1, 参数2, 参数3)

static

static的特点:被该类的所有对象所共享(判定是否使用static的关键)

  • 一旦一个普通成员变量被static修饰,该成员变量就称之为静态成员变量(静态变量),该成员变量就不再储存于对象中了,而是单独储存一份,被该类所有成员共享。
  • 一旦一个普通成员方法被static修饰,该成员方法就称之为静态成员方法(静态方法),跟普通方法没什么区别。

访问:可以直接通过类名访问static修饰的成员变量和成员方法
1、只有静态成员能用类名.来访问(官方推荐)
2、普通非静态成员只能用对象名.来访问

执行时机:随着类加载而加载
1、static修饰的成员变量,类加载时在方法区分配存储空间,并赋予默认初值
2、static修饰的成员方法,类加载完毕,就可以通过类名访问

优先于对象而存在,当我们首次访问类的静态成员变量或者静态成员方法的时候,此时会触发类的加载。即任何时候都可以访问,不依赖对象而存在。

注意事项:
1、静态方法中不能访问非静态的成员变量和非静态的成员方法
2、静态方法中不能使用this
3、不管静态方法还是非静态方法中,都不能使用static关键字(static关键字不能使用在方法体中)
也就是说只是无法访问当前对象的普通成员变量和当前多项的普通成员方法。但是,我们可以在静态方法中自己创建出的对象上访问其普通成员变量或普通成员方法。

被static修饰的成员的存储位置:方法区中

static使用场景
1、当我们希望,某个成员变量的值,被该类的所有对象所共享,此时可以使用static修饰这个成员变量。
2、通常当我们需要定义一个方便被别人使用工具方法的时候,此时将该方法定义成静态方法

静态成员变量 普通成员变量
所属不同 静态变量属于类,所以也称为类变量 成员变量属于对象,所以也称为实例变量
内存中的位置不同 静态变量储存于方法区 成员变量储存于堆内存
内存中出现的时间不同 静态变量随着类的加载而加载,随着类的消失而消失 成员变量随着对象的创建而存在,随着对象的消失而消失
访问方式不同 静态变量可以通过类名调用,也可以通过对象调用 成员按量只能通过对象名调用

代码块codeblock

定义:在Java中,使用{}括起来的代码被称为代码块。

在嵌套的代码块中,不能定义同名的局部变量
1、局部代码块

  • 定义位置:定义在方法体中,通常开发中没人用
  • 执行时机:随着所在方法的执行而执行
  • 优点:限定局部变量生命周期,及早释放,提高内存利用率(但是该效果可以忽略不记,且极难维护,所以实际开发不要使用)

2、构造代码块

  • 定义位置:定义在类中方法体之外
  • 执行时机:每次创建对象的时候必执行,而且先于构造方法执行。可以用来创建对象时给成员变量赋初值。同时构造代码块和成员变量的初始化语句执行先后顺序取决于定义的先后顺序(通常实际开发中初始化语句写在前面)。
  • 使用场景:
    1、可以利用构造代码块,在构造代码块中,访问成员变量,在创建成员变量的时候给该成员变量赋初值。
    2、多个构造方法中都需要执行一段相同的代码,我们就可以把这些代码放在构造代码块中。
  • 注意事项:如果有多个构造代码块,则这多个构造代码块,按照书写的先后顺序执行。

到目前为止,我们有3种方式给一个成员变量赋初值:
1、成员变量的初始化语句
2、构造代码块
3、构造方法

3、静态代码块

  • 定义位置:类中方法体之外,但同时代码块被static关键字修饰
  • 执行时机:随类加载而执行。只要类加载,静态代码块就会执行
  • 注意事项
    1、静态代码块,属于静态上下文,在静态代码块中,不能访问非静态的成员变量和成员方法
    2、因为随着类加载而加载,所以在同一个jvm中,只会执行一次(因为一个类只会被一个jvm最多加载一次)。
  • 使用场景:当代码在整个程序运行过程中只需要执行一次,这样的代码我们就可以放在静态代码块中

4、同步代码块(多线程的时候学习)

package

在Java源程序文件的第一行使用package声明可以使文件中定义的类成为指定包的成员。
虽然,在Java文件中,我们可以不使用package关键字来声明一个Java文件中定义的类所属的包,但这不意味着这个类不属于某个包,没有显示使用package关键字声明其所属包的类,都属于Java语言中的默认包。

  • 作用
    1、类比于操作系统中用来组织文件的文件夹,java语言中,用包来组织类。
    2、包还可以用来解决类的同名问题,不同包下可以存在同名类
  • 语法
    package 包名;
    package com.csdn.exercise;
    package 关键在后跟包名,且这条语句必须放在java文件第一条语句的位置。
  • 包的命名方式:域名反转的方式
  • 注意事项:当一个java文件中,没有package关键字定义类所在包时,类所属的包时默认包。

import关键字

我们可以在不同的包中,定义同名类,在Java语言中,仅凭类名我们时无法唯一确定一个类。所以引入全限定类名,来唯一确定类。
在类名前面加上类所属的包名,中间用句点“.”分隔,称为类的完全限定名(Full Qualified Name),简称类的限定名。

  • 作用:当在类体中使用了与当前类不同包的类名时,编译器编译时因为无法找到该类的定义而失败,使用import声明,为编译器提供该类的定义信息。
    1、在同一个包下找到了类,则默认使用该类。
    2、一旦用import声明了另一个包下同名的类,则使用那个类。
  • 语法:import <类的完全限定名>;
    import声明提供了一种包的智能导入方式:import <包名>.*;包中的类将根据需要导入,避免使用多条import声明。按需导入:只会导入当前包中没有的类
    import语句后跟类的全限定名:类的全限定名是指包名+类名,在java语言中,包名+类名才能唯一确定一个类。
    import com.csdn.exercise.Demo1;
  • 注意事项
    1、import声明一般紧跟在package声明之后,必须在类声明之前
    2、Java语言核心包java.lang包中的类将被隐式导入,可以直接使用其中的类 。
    3、可以使用import <包名>.*;一次导入一个包下的多个类 ,但是这种方式不会自动嵌套导入子包中的类。

访问权限修饰符

修饰类中成员(成员变量和成员方法)

  • public 公共访问权限
    任意类均访问,实际就是没有限制访问权限
  • protected 受保护的访问权限
    1、类体中:可以直接访问、可以创建对象访问
    2、同包其他类:可以通过创建对象访问
    3、非同包的类:在非同包的子类中,直接访问父类中的protected修饰的成员。非同包子类中,创建该子类对象访问父类中的protected修饰的成员。不同包的中,在有一部分类中,无法访问到具有protected权限的成员,还有一部分可以访问到(子类)??在继承中会讲。
  • default 默认权限,隐式定义
    1、类体中:可以直接访问、可以通过创建对象访问
    2、同包其他类:可以通过创建对象访问
    3、非同包的类:无法通过创建对象访问
  • private 最小的访问权限,仅对同类中的其他成员可见
    1、类体中:可以直接访问、可以通过创建对象访问
    2、同包其他类:无法通过创建对象的方式访问
    3、非同包的类:无法通过创建对象的方式访问

修饰类

  • public 对其他任意类可见
  • 类不具有protected访问权限
  • default 对同包中其他类可见
  • 类不具有私有private访问权限

为什么要使用访问控制修饰符?private
1、使用户不要触碰他们“不该”触碰的代码(private)
2、类库设计者可以安全的修改实现细节

面向对象三大特征

封装

概念:是指将数据和基于数据的操作封装在一起。

好处:
1、数据被保护在内部(结合访问权限)。
2、系统的其他部分只有通过在数据外面 的被授权的操作才能够进行交互 (结合访问权限理解)。
3、目的在于将类使用者class user和类设计者class creator分开。(结合访问权限理解)。

在代码中的体现
1、在定义成员变量和成员方法的时候,要考虑,通常只赋予其最小的访问权限。
2、如果用private修饰成员变量,通常还要考虑提供对应的get,set方法。

  • public get: 获取某一个成员变量的值
  • public set: 修改某一个成员变量的值
  • 一个类中可以定义多个私有成员变量,而每一个成员变量,都对应一个get和set方法。

针对boolean类型的私有成员变量
比如boolean male;get方法的命名:isMale()

get,set方法带来的好处:
1.通过get,set,可以访问对象的私有成员变量值。
2.通过get,set方法,完成对成员变量访问的读,写分离。
3.正是因为,外部只能通过get,set方法来访问私有成员变量, 可以以这种方式控制外部,对成员变量值访问。

继承

基本知识

含义:表示java中的一种代码复用机制。
表示子类与父类两种数据类型之间的一种继承或者说从属关系,或者说is-a的关系
语法:class 子类名 extends 父类名 {}

相关概念:子类也叫派生类或导出类,父类也叫超类或基类。

优缺点

  • 优点
    1、代码复用。复用已有的类定义代码(成员变量定义和成员方法定义)。
    2、提高了代码的可维护性。父类中的代码可以被多个子类复用,被复用代码只定义在父类中,只有一份。
    3、弱化了java语言中的类型约束。父类类型的引用可以指向子类类型的实例。
  • 缺点
    父类的修改可能会出现在所有子类中(我们无法选择这些修改可以反应在,哪些子类中,不反应在哪些子类中)。

java语言中继承的特点:单重继承,extends关键字后面只能跟一个类名。(多重继承后面讲)

继承的注意事项
1、子类只能访问父类所有非私有的成员(成员方法和成员变量) ,不是不能继承,只是不能访问。
2、子类不会继承父类的构造方法 。

子类对象的初始化

研究的问题:
子类对象中,现在有两部分数据:父类中声明的成员变量的值,子类中自己定义的成员变量的值。这两部分数据,初始化(赋初值)的一个先后顺序问题。

先后顺序的规定:java语言要求:必须先初始化父类成员变量的值,在初始化子类成员变量的值

如何理解这个顺序:
1、子类继承父类,父在先,子在后。父类成员变量先初始化,然后才是子类自己定义的成员变量值的初始化。
2、初始化子类成员的时候,子类成员变量的初值,和父类成员变量的值有关系

如何实现?
保证父类的的构造方法先执行,子类的构造方法。
两种方式实现:

  • 隐式初始化(由jvm保证先初始化父类成员)
    1、父类中存在默认构造方法。
    2、子类构造方法在执行时没有显示的调用父类的其他构造方法。
    3、则子类构造方法执行前,会自动调用父类的默认构造方法。
  • 显式初始化(由我们自己写代码保证)
    1、我们自己在子类构造方法中通过super(实参列表)的方式调用父类构造方法。
    2、super语句必须处在子类构造方法的第一条语句的位置。
    3、若父类没有默认构造方法,子类构造方法必须在第一条语句的位置,通过super调用副楼某个构造方法。

super关键字
super代表对象的内存空间的标识,也可以理解为父类对象的引用。
作用:
1、访问父类对象的成员变量值
2、访问父类中定义的成员方法
3、调用父类的构造方法

域的隐藏问题

子类中是可以定义和父类成员变量,同名的成员变量。
1、如果,子类中定义了和父类中成员变量同名的成员变量

  • 如果在方法体中,通过同名成员的变量名,访问父类和子类定义的同名成员变量值。
  • 如果是在父类的方法中,访问同名成员变量,访问到的就是父类的成员变量值。
  • 如果是在子类的方法中,访问同名成员变量,访问到的就是子类成员变量的值。

2、在子类对象上,对象.成员变量的方式来访问成员变量的值

  • 先在子类对象,子类自己定义的成员变量中找,找到就访问。
  • 如果没找到,就继续去父类对象中,相应的成员变量,找到就访问。

3、在子类类体中,可以通过super.变量名,访问到父类对象的同名成员变量的值。

方法覆盖

子类中可以定义和父类中一模一样的方法
1、如果子类中定义了和父类一模一样的方法

  • 在子类类体中,调用该方法,调用的是子类中定义的方法。在子类类体中,可以通过super.方法,访问到父类中定义的那个和子类相同的方法。

  • 在父类类体中,调用该方法,调用的到的也是子类中定义的方法。

2、当我们在某个子类对象上调用一个方法的时候,jvm是如何确定执行哪个方法的

  • 首先,会在子类对象对应的子类中去找,要执行的方法,如果找到,就直接执行。
  • 如果在子类中,没有找到,要执行的目标方法,才会在父类中这个方法。

方法覆盖的条件

  • 方法的权限修饰符:子类方法的权限不能小于父类方法的权限。
  • 方法返回值类型:1、子类方法返回值类型和父类方法返回值类型相同。2、子类方法返回值类型是父类方法返回值的子类类型。
  • 方法签名:方法名相同并且方法的形参列表相同。

方法覆盖的作用:在子类类体中,修改父类中定义方法的实现(注意并没有在父类中去修改父类中的方法实现)。

注意事项:1、父类的私有方法不能被子类覆盖。2、静态方法不能被覆盖。

final关键字

  • 修饰类:被final修饰的类不能被其他类继承。
  • 修饰方法:被final修饰的方法不能被覆盖。
  • 修饰变量
    1、修饰成员变量:对象创建完毕之前被赋值,且仅能被赋值一次。
    2、修饰局部变量:使用之前必须被赋值,且仅能被赋值一次。
    3、引用变量:final修饰引用变量的时候,引用变量的值,就不能发生改变了,但是引用变量所指向的对象的成员变量的值不受影响。(因为引用变量储存的是内存地址,即内存地址不变,但是内存地址指向的对象可以变)。

多态

多态指“同一个对象”的行为,在不同的时刻或条件下,表现出不同的效果。(这里的同一个对象之所以打引号,其实指的是同一个引用变量)。

多态的前提条件:
1、继承
2、方法覆盖(重写)
3、父类引用指向子类实例

成员的访问特征(与覆盖中成员变量成员方法结合来看)

  • 成员变量:编译看左边,运行看左边
  • 成员方法:编译看左边,运行看右边

理解

  • 成员变量
    1、成员变量值,作为对象的属性值,描述对象的外貌。
    2、多态中,父类引用指向子类实例,相当于给子类对象披上了父类的外衣
    3、因此,子类对象的外貌,看起来就是父类对象,因此多态成员变量的访问特征是编译看左边,运行看左边。
  • 成员方法
    虽然看起来,是父类对象的样子,但是因为,父类引用实际指向的是一个子类对象,因此,其行为,表现的仍是子类对象的行为。

多态的好处:1、提高了程序的维护性(由继承保证) 。2、提高了程序的扩展性(由多态保证) 。

多态的弊端:不能访问子类特有功能(因为父类引用指向子类实例)
解决方法:强制类型转化

  • 子类引用——>父类引用(向上转型)
    编译器默认允许
  • 父类引用 ——>子类引用(向下转型)
    通过强制类型转化来完成

ClassCastException异常
instanceof关键字:判断对象所属类型是否是目标类型。
注意事项:所有的引用变量都可以被赋值null。
那么null instanceof 目标类型的计算结果都是false。

抽象类

概念:包含有抽象方法的类或被abstract修饰的类 。
注意事项:
1、抽象类和抽象方法必须用abstract关键字修饰 。
abstract class 类名 {}
public abstract void eat();
2、抽象类不一定有抽象方法,有抽象方法的类一定是抽象类 。

抽象类特征

  • 抽象类不能直接实例化 ,只能间接实例化
    抽象类类型 引用变量 = new 抽象子类
    抽象类引用指向抽象子类,再在子类当中实现相应方法(利用抽象类引用,访问抽象类中定义的行为).
  • 抽象类的子类可以是抽象类,也可以是具体类(当子类是具体类时,必须实现父类中所有的抽象方法) 。

抽象类的组成特征

  • 成员变量:同普通类
  • 构造方法:和普通类相同
    抽象类不能直接实例化,还有构造方法的原因。(抽象类中可以定义成员变量,为了能在子类,方便初始化抽象父类中成员变量的值。)
  • 成员方法:既可以有抽象方法,也可以有非抽象方法(主要用来代码复用)。

和abstract冲突的关键字:private、static、final
abstract定义抽象方法,对于抽象方法而言,如果代码中要使用,其实永远是通过多态,调用的是子类中,覆盖实现的抽象父类的抽象方法。
而被private,final,static福安剪子修饰的方法,都不能再子类中被覆盖,于是意味着这些方法,无法在程序中运行。

接口

概念:表示一组特殊功能的集合(往往只包含这组特殊功能的声明)。
由于单重继承的限制,使用接口来表示一组特殊集合。
在java语言中,接口interface和类处于同等地位都表示数据类型

类和接口的对比

  • 类定义了一个数据集合(成员变量)和基于这个数据集合的一组操作(成员方法),操作之间有一定联系(操作同一个数据集合)。
  • 接口中通常只包含方法声明,即接口中的方法都是抽象方法(jdk8之前)
  • 接口中声明的方法,就纯粹表示一组功能的集合,功能相互之间可以没有啥联系,比较松散

语法:接口用关键字interface表示 格式:interface 接口名 {}

类和接口的关系
1、类可以实现接口,类实现接口用implements表示
2、实现关系,其实是一种实质性的继承关系

接口特征
1、接口不能直接实例化,只能间接实例化
2、接口的子类,可以是抽象类也可以是具体类 (具体类必须实现接口中的所有抽象方法)

接口的组成特征
1、无构造方法
2、只能是常量,默认修饰符public static final,通过接口名.的方式访问
3、成员方法:只能是抽象方法,默认修饰符public abstract (jdk8之前)

接口实现了java语言的多重继承
1、接口与接口之间可以是多重继承
2、一个类可以在继承另一个类的情况下,实现多个接口(实现关系,也是一种实质上的继承关系)

抽象类 VS 接口
成员区别

  • 成员变量
    1、抽象类的成员变量,可以是变量可以是常量
    2、而接口中的成员变量,只能是常量
  • 成员方法
    1、抽象类的成员方法,可以是抽象方法,也可以是非抽象方法
    2、接口中的成员方法,只能是抽象方法(jdk8之前)

关系的区别

  • 类与抽象类
    继承关系,而且是单重继承
  • 类与接口
    实现关系,一个类可以实现多个接口
  • 接口与接口
    继承关系,接口与接口之间可以实现多重继承

设计理念的区别

  • 抽象类 被继承体现的是:”is a”的关系。共性功能 (抽象类中定义的是大家共有的特性,共享的成员)。
  • 接口 被实现体现的是:"like a”的关系。扩展功能 (表示功能的集合)

JDK8中引入的特殊方法

  • default默认方法
    在接口中定义的非静态的可以有方法体的方法,而且在接口中添加默认方法,不会影响实现接口的子类,并可以在子类中调用。
    默认方法存在的意义是一种折中,向类中添加默认方法不会影响那些之前已经实现的方法。
  • static静态方法
    接口中定义的,可以有方法体的静态方法,只能在定义静态方法的接口或者通过定义接口的接口名.静态方法()的方式访问。
    静态方法存在的意义类似于我们之前的工具方法,实际开发中很少用到。

内部类

概念:定义在其他类内部的类就称为内部类。

访问特征:
1、内部类可以直接访问外部类的成员,包括私有。
2、外部类要访问内部类的成员,必须创建对象。
此处的外部类是包含内部类的类。

按照内部类在类中定义的位置不同

  • 成员位置内部类
    定义在类中,方法体之外,可以看做是外部类的一个普通成员,这意味着,内部类依赖于外部类对象而存在。
    创建内部类对象:外部类中,和创建普通类对象没啥区别。外部类的外部外部类名.内部类名 对象名 = 外部类对象.内部类对象
    成员内部类常用修饰符:
    private 保证成员位置内部类只对其外部类可见。
    static 整个内部类,就变成了一个静态上下文,内部类不在依赖于外部类对象而存在。

  • 局部位置内部类
    定义在类中的,方法体内。
    局部内部类,只能在定义内部类的方法体中创建该内部类对象。
    局部内部类的访问特征:
    局部内部类除了有所有内部类共有的访问特征之外,还有一个特征就是,局部内部类可以访问方法体中的局部变量。但是局部内部类只能访问final的局部变量。(定义在方法中的局部变量,没有被final修饰仅赋值一次时,默认为final)
    原因:
    1、核心原因生命周期的冲突问题
    2、局部变量存储在栈帧中,栈帧随方法执行的结束,而被销毁
    3、而局部内部类对象并不一定随着方法的执行而被销毁
    4、即方法执行结束后,局部变量已经不存在,而匿名内部内对象,还活着,因此它就可以去访问那个已经不存在的局部变量

  • 匿名内部类对象
    本质:是一个匿名(继承了类或者实现了接口的 匿名子类)对象。
    优点:不管是成员或局部位置内部类,我们要使用内部类都分成了2步:定义内部类,创建内部类对象。通过定义匿名内部类对象,我们可以将上面的2步变为1步。
    前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类。
    语法:new 类名或者接口名() {重写方法;};
    匿名内部类对象成员的访问:一个匿名内部类对象,因为是个匿名对象,所以每访问一次成员,都需要创建一个对象(除非用一个引用变量指向该对象),即只能在创建匿名对象时候访问匿名对象一次,且仅一次。
    使用场景:
    1、new 类名或者接口名() {重写方法;}.方法;只使用某抽象类,或者接口子类对象一次的情况下使用。方法的形式参数,是引用类型的情况重点是接口的情况,方法返回一个接口类型的子类对象的时候。
    2、类名或者接口名 命名 = new 类名或者接口名() {重写方法;};命名.方法;也可以用一个引用变量,指向一个匿名内部类对象,相当于多态,但是不能调用子类中单独定义的方法。

类、抽象类、内部类等的访问相关问题(重点)

后续添加ing

在这里插入代码片

猜你喜欢

转载自blog.csdn.net/Re0_M/article/details/109082799
今日推荐