菜鸡的Java笔记 第二十六 - java 内部类
/* innerClass
从实际的开发来看,真正写到内部类的时候是在很久以后了,短期内如果是自己编写代码,几乎是见不到内部类出现的
讲解它的目的第一个是为了解释概念,另外一个就是也是为后期的一些复杂程序做铺垫
所谓的内部类指的是在一个类的内部(外部类)定义类结构的一种处理形式
*/
/* 内部类的基本概念
类的组成永远都是只有两点:成员(Field),方法(Method),但是几乎所有的程序里面斗不会对嵌套的结构有任何的限定
所以内部类指的是在一个类的内部可以继续嵌套其他类结构的一种形式代码
并且从理论上来讲可以一直嵌套下去
下面首先来看一下内部类的基本形式
范例:观察内部类代码
class Outer{ // 外部类
private String info = "Hello World!":
class lnner{ // 内部类
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
public void fun(){
lnner in = new lnner(): //实例化内部类对象
in.print(): // 调用内部类的方法
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():
out.fun():
}
}
// 结果 Hello World!
类本身的核心组成就应该是属性和方法,但是如果引用了内部类,就相当于破坏了这样的程序结构
所以内部类所带来的最为严重的问题就在于程序结构的破坏,但是破坏了那么也应该有一些收益
那么内部类的好处在哪里呢?为了观察出内部类的好处,那么下面将内部类拿出来,变为两个类
范例:内部类拿出来
class Outer{ // 外部类
private String info = "Hello World!": public void fun(){
// 将当前对象传递到内部类之中
lnner in = new lnner(this): //实例化内部类对象
in.print(): // 调用内部类的方法
}
// 为in定义一个getter方法
public String getlnfo(){
return info:
}
}
class lnner{ // 内部类
private Outer temp: // 此处应该接收外部类实例化好的Outer类对象
public lnner(Outer temp){
this.temp = temp:
}
public void print(){
// 此处需要访问外部类中的私有属性,所以不能够直接输出属性,需要Outer类提供有getter
// 方法应该由对象进行调用,所以现在需要有一个实例化对象
// 相当于就是外部的out。getlnfo()
System,out.println(this.temp.getlnfo()): // 输出info 属性内容
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():
out.fun():
}
}
// 结果 Hello World!
代码修改完成之后实际上就可以感受到内部类的最大好处是可以直接进行外部类中私有属性的直接访问
那么清楚内部类的基本定义之后,实际上现在又会存在有一下几个问题:
1.在编写代码一直强调:只要是属性的访问,一定要加上“this ”,这个时候由于属性是外部类中的
所以要想操作this 那么就必须使用“外部类.this.属性” ( 上面: Outer.this.info)
如果内部类中的方法直接采用了“this.属于”表示的是什么,只是本类(内部类)中的属性
2.以上的代码发现内部类可以方便访问外部类中的私有属性,同时发现外部类中的fun()方法里面也占着内部类的对象
那么内部类的私有属性外部类也可以直接利用对象访问
class Outer{ // 外部类
private String info = "Hello World!":
class lnner{ // 内部类
private String msg = "+++++++++":// 内部类的私有属性
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
public void fun(){
lnner in = new lnner(): //实例化内部类对象
in.print(): // 调用内部类的方法
System.out.println(in.msg):// 内部类对象直接调用属性
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():
out.fun():
}
}
/*
结果
Hello World!
++++++++++++
*/
内部类与外部类之间的私有属性都是可以直接进行访问的,这一点要比分为两个类更加的方便
3.现在发现实例化内部类的对象操作都是在外部类中的fun()方法里面完成的
那么如果现在不希望通过外部类的方法操作内部类,那么也可以根据一下的语法,直接在其他类实例化内部类对象
语法结构:
外部类名称.内部类名称 对象名称 = new 外部类().内部类()
内部类的标准的名称应该是“外部类.内部类”,只不过“.”不可能直接出现在文件中
所以java 将其进行了转换,在文件名称中使用“$”来代替“.”
class Outer{ // 外部类
private String info = "Hello World!":
class lnner{ // 内部类
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
Outer.lnner in = new Outer().new lnner():
in.print():
}
}
// 结果 Hello World!
4.内部类中可以利用private定义私有内部类:
class Outer{ // 外部类
private String info = "Hello World!":
private class lnner{ // 内部类
public void print(){
System,out.println(Outer.this.info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
Outer.lnner in = new Outer().new lnner():
in.print():
}
}
// 结果: 出错
对于内部类的概念与它的结构有个先期的认识即可
*/
/* 内部类定义深入
在之前使用的都是普通类的形式进行了内部类的定义,实际上在内部结构上也可以应用在抽象类和接口上
范例:在抽象类上定义内部类
abstract class AbstractOuter{ // 抽象类的外部类
public abstract void peintOuter();
abstract class AbstractInner{ // 抽象内部类
public abstract void printInner();
}
class Inner{ // 普通的内部类
public void print(){
System.out.println("加油!");
}
}
}
class OuterImpl extends AbstractOuter{ // 继承了外部抽象类
public void peintOuter(){
new Inner().print(); // 实例化内部类的对象调用方法
}
}
public class innerClass{
public static void main(String args[]){
AbstractOuter out = new OuterImpl();
out.peintOuter();
}
}
在定义内部抽象类的时候是不会影响到子类的,也就是说子类只需要覆写它所继承的抽象类中的抽象方法即可
范例:定义内部抽象类的子类
abstract class AbstractOuter{ // 抽象类的外部类
public abstract void peintOuter();
abstract class AbstractInner{ // 抽象内部类
public abstract void printInner();
}
class Inner{ // 普通的内部类
public void print(){
System.out.println("加油!");
}
}
}
class OuterImpl extends AbstractOuter{ // 继承了外部抽象类
public void peintOuter(){
new Inner().print(); // 实例化内部类的对象调用方法
}
class InnerImpl extends AbstractInner{ // 内部抽象类
public void printInner(){
new Inner().print();
}
}
}
public class innerClass{
public static void main(String args[]){
AbstractOuter.AbstractInner in = new OuterImpl(),new InnerImpl();
in.peintOuter();
}
}
除了内部抽象类之外也可以实现内部的接口定义
范例:定义内部接口
interface IOuter{
public void peintOuter();
interface IInner{
public void printInner();
}
class B{
public void print(){
System.out.println("++++++++");
}
}
}
class OuterImpl implements IOuter{
public void peintOuter(){
class InnerImpl implements IInner{
public void printInner(){
new B().print();
}
}
}
}
public class innerClass{
public static void main(String args[]){
IOuter.IInner in = new OuterImpl().new InnerImpl();
in.printInner();
}
}
内部类完整的打破了程序结构定义要求,也就是说程序里面没有对内部类的结构做出任何的限制,只要该定义符合语法要求即可使用
*/
/* 利用static定义内部类
利用static定义的属性或者是方法,是不受到类的控制的,也就是说相当于是一个局外的结构
所以如果内部类上用了static定义,那么就表示此内部类变为了一个外部类,但是需要注意的是,如果它使用了static定义,那么只能够访问外部类中的static属性
范例:利用static定义内部类
class Outer{ // 外部类
private static String info = "Hello World!":
static class lnner{ // 内部类
public void print(){
System.out.println(info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){ }
}
那么既然现在static的内部类变为了外部类,外部类就可以被其他类直接进行操作
但是这个时候的实例化对象格式:
外部类名称.内部类名称 对象名称 = new 外部类.内部类():
加上了static之后,那么实际上也就表示这个内部类的名字就成了“外部类.内部类”
范例:实例化内部类对象
class Outer{ // 外部类
private static String info = "Hello World!":
static class lnner{ // 内部类
public void print(){
System.out.println(info): // 输出info 属性内容
}
}
}
public class innerClass{
public static void main(String args[]){
Outer.lnner oi = new Outer.lnner():
oi.print():
}
}
// 结果 Hello World!
以后见到程序类库中出现有“Xxxx.Xxxx”就表示内部类
对于 static 定义内部类的形式在实际开发之中使用很多,但是也可以在接口上使用,即:接口内部可以使用 static 定义外部接口
范例:
interface IOuter{
static interface IInner{ // 静态的内部接口
public void print();
}
}
class InnerImpl implements IOuter.IInner{
public void print(){
System.ou.println("+++++++++");
}
}
public class innerClass{
public static void main(String args[]){
IOuter.IInner oi = new InnerImpl():
oi.print():
}
}
*/
/* 方法中定义内部类
理论上内部类可以在任何的位置上定义,包括:代码块中,类中,方法中。所以在实际的开发之中,有可能直接在方法里使用内部类
范例:观察方法中定义内部类
class Outer{ // 外部类
private String info = "Hello World!":
public void dun(int temp){ // 方法中的参数
double sal = 9000.0: // 方法中定义的普通变量
class lnner{ // 内部类,方法中定义
public void print(){
System.out.println("Outer类中的info属性= "+Outer.this.info):
System.out.println("fun()方法中的参数,temp = "+temp):
System.out.println("fun()方法定义的临时变量,sal ="+sal):
}
}
new lnner().print():// 实例化内部类对象,调用方法输出
}
}
public class innerClass{
public static void main(String args[]){
Outer out = new Outer():// 实例化Outer类对象
out.fun(100):
}
}
/*
结果
Outer类中的info属性= Hello World!
fun()方法中的参数,temp = 100
fun()方法定义的临时变量,sal = 9000.0
*/
注意:现在使用的是JDK1.8版本
那么这个版本的好处是避免了一些复杂的细节,之所以会避免是为了整体的设计考虑的,而以上的代码,在JDK1.7时就会出现问题
因为在JDK1.7以前有一个约定,如果一个方法中定义了内部类,那么这个内部类要想访问方法的参数或者是定义的变量,则参数或者是变量前必须加上final
之所以可以不加final了,主要是因为那个Lamde与方法引用一起出现所造成的新局面
*/
/* anonymousInternal 匿名内部类
匿名内部类的使用
内容
匿名内部类 = 没有名字的内部类
任何的技术出现都有它可以解决的问题,所以下面首先来分析一下没有匿名内部类的情况
范例:观察程序代码的问题
interface A{// 定义了一个接口
public void ptintA();
}
class X implements A{
public void ptintA(){
System.out.println("AAAAAAAAAAAAAAA");
}
}
publlic class anonymousInternal{
publlic static void main(String args[]){
A a = new X();
a.ptintA();
}
}
有了一个接口,而后为接口定义了一个子类,在主类中利用对象的向上转型进行对象实例化操作
但是现在有一个问题出现了,本程序中为接口A定义了一个子类X,但是假设说此时的这个X子类只使用唯一的一次
那么有必要将其定义成一个单独的类吗?那么此时的设计就有些夸张了。
那么就可以利用匿名内部类的概念来解决,而且匿名内部类必须以抽象类或接口为前提进行使用
范例;使用匿名内部类
interface A{// 定义了一个接口
public void ptintA();
}
public class anonymousInternal{
public static void main(String args[]){
A a = new A(){ // 匿名内部类
public void ptintA(){
System.out.println("***********************");
}
}
a.ptintA();
}
}
现在的基本感觉此语法很槽糕,程序的结构很混乱
范例:
abstract class AbstractA{
private String mdg = "+++++++++++++";
public String getMsg(){
return this.msg;
}public abstract void print();
}
public class anonymousInternal{
public static void main(String args[]){
AbstractA a = new AbstractA(){ // 匿名内部类
public void ptint(){
System.out.println(this.getMsg());
}
}
a.ptintA();
}
}
匿名内部类的最大特点是可以减少类的定义个数,所以在以后的开发之中会大量的使用匿名内部类来进行某些接口子类的定义
这一点在后面讲解的多线程开发之中非常有用处,同时匿名内部类也是 Lembda 表达式的原始雏形
总结
可以看懂匿名内部类就够了,其他的慢慢随着代码的编写经验的增长自然就会了
*/
/* 总结
1.不要去考虑怎么用,一般的开发很少会用到,但是会使用
2.内部类先看明白它的语法形式
*/
菜鸡的Java笔记 第二十六 - java 内部类的更多相关文章
- 菜鸡的Java笔记 第二十八 - java 包的定义
包的主要作用以及定义 包的导入操作 系统常见的开发包 jar 程序命令 包的定义 在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...
- 菜鸡的Java笔记 第十六 - java 引用传递
referenceDelivery 引用传递是整个java 的精髓,也是所有初学者最难学的地方 引用的本质:同一块堆内存可以被不同的栈内存所指向 下面通过三道程序来进行引用传 ...
- 菜鸡的Java笔记 第二十四 - java 接口的基本定义
1.接口的基本定义以及使用形式 2.与接口有关的设计模式的初步认识 3.接口与抽象类的区别 接口与抽象类相比,接口的使用几率是最高的,所有的 ...
- 菜鸡的Java笔记 第二十二 - java 对象多态性
本次只是围绕着多态性的概念来进行讲解,但是所讲解的代码与实际的开发几乎没有关系,而且多态一定是在继承性的基础上才可以操作的, 而本次将使用类继承的关系来描述多态的性质,实际的开发中不会出 ...
- 菜鸡的Java笔记 第二十九 - java 单例设计模式
SingleCase 单例设计模式 1.单例设计模式的特点 2.多例设计模式的特点 内容 单例设计模式 现在如果说有这么一个程序类 class S ...
- “全栈2019”Java多线程第二十六章:同步方法生产者与消费者线程
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 菜鸡的Java笔记 第二十五 wrapperClass 包装类
wrapperClass 包装类 1.包装类的特点 2.装箱与拆箱操作 3.数据转型处理 内容 Object 类可以接收 ...
- 菜鸡的Java笔记 第二十 - java 方法的覆写
1.方法的覆写 当子类定义了与父类中的完全一样的方法时(方法名称,参数类型以及个数,返回值类型)这样的操作就称为方法的覆写 范例:观察方法的覆写 class A{ public void ...
- 菜鸡的Java笔记 第十九 - java 继承
继承性的主要目的,继承的实现,继承的限制 继承是面向对象中的第二大主要特点,其核心的本质在于:可以将父类的功能一直沿用下去 为什么需要继承? ...
随机推荐
- 带你读Paper丨分析ViT尚存问题和相对应的解决方案
摘要:针对ViT现状,分析ViT尚存问题和相对应的解决方案,和相关论文idea汇总. 本文分享自华为云社区<[ViT]目前Vision Transformer遇到的问题和克服方法的相关论文汇总& ...
- css新增属性之边框
css3新增属性 边框属性 背景属性 文字属性 颜色属性 边框属性 属性 说明 border-radius 设置边框圆角 border-image 设置图像边框 border-shadow 设置边框阴 ...
- 测试开发【提测平台】分享12-掌握日期组件&列表状态格式化最终实现提测管理多条件搜索展示功能
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本章内容思维导图如下,由于需要各种状态下的菜单操作,所以需要先实现提测信息的列表基础页面,然后再推进其他需求开发 基本知识点学习 Date ...
- 前端必会的Javascript经典面试题
这是前端最基础的问题,也是在面试中难倒无数同学的经典问题 01. Javascript 数据类型 Javascript 数据类型 = 基本类型 + 引用类型 ES6 之前 5 + 1 = 6 种 ES ...
- 洛谷3203 弹飞绵羊(LCT)
据说这个题当年的正解是分块qwq 根据题目所说,对于题目中的弹力系数,就相当于一条边,那么对于"跳出去"这个限制,我们可以选择建造一个新点\(n+1\)表示结束,那么每次,求一个点 ...
- 小数的十进制和二进数转换 “无限不循环”小数的IEEE 754表示
十进制 -> 二进制 将整数部分和小数部分分开处理 例:3.125(10) 其整数部分为11(2) 小数部分按照下面的步骤求解: 0.125 x 2 = 0.25 取0 0.250 x 2 = ...
- Visual Studio Debug only user code with Just My Code
Debug only user code with Just My Code By default, the debugger skips over non-user code (if you wan ...
- CentOS 压缩解压
目录 命令 tar gzip.gunzip bzip2.bunzip2 zip.unzip 命令组合 打包:将多个文件合成一个总的文件,这个总的文件通常称为"归档". 压缩:将一个 ...
- Java:TreeMap类小记
Java:TreeMap类小记 对 Java 中的 TreeMap类,做一个微不足道的小小小小记 概述 前言:之前已经小小分析了一波 HashMap类.HashTable类.ConcurrentHas ...
- [Beta]the Agiles Scrum Meeting 5
会议时间:2020.5.19 20:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 issue yjy 为评测机增加更多评测指标 评测部分增加更多评测指标 tq 为评测机增加更多评测指标 ...