菜鸡的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 继承
继承性的主要目的,继承的实现,继承的限制 继承是面向对象中的第二大主要特点,其核心的本质在于:可以将父类的功能一直沿用下去 为什么需要继承? ...
随机推荐
- Dapr + .NET Core实战(十一)单机Dapr集群
如何单机部署Dapr集群 第十篇讲过了K8S集群下如何使用Dapr运行程序,但是很多人一直在问如何单机下进行Dapr的负载,这节课我们来聊聊如何单机进行Dapr的负载. 首先要说的是单机下,通过 da ...
- SpringPlugin-Core在业务中的应用
前言 一直负责部门的订单模块,从php转到Java也是如此,换了一种语言来实现订单相关功能.那么Spring里有很多已经搭建好基础模块的设计模式来帮助我们解耦实际业务中的逻辑,用起来非常的方便!就比如 ...
- 函数式编程 —— 将 JS 方法函数化
前言 JS 调用方法的风格为 obj.method(...),例如 str.indexOf(...),arr.slice(...).但有时出于某些目的,我们不希望这种风格.例如 Node.js 的源码 ...
- 在Vue中使用JSX,很easy的
摘要:JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javasc ...
- Python笔记_1语法总结
前言导读 本章知识点是我在最初期听python视频教程的时候整理总结的笔记 对python语法的认识对以后代码的解读有着很大的帮助. 1 新建python命名规则 新建项目名 :数字编号 项目名称 新 ...
- FFT 的一些技巧
三次变两次 FFT 我们发现: \[(F(x)+iG(x))^2=F(x)^2-G(x)^2+2iF(x)G(x) \] 也就是说,我们把 \(F(x)\) 作为实部,\(G(x)\) 作为虚部,那么 ...
- 洛谷4895 独钓寒江雪 (树哈希+dp+组合)
qwq 首先,如果是没有要求本质不同的话,那么还是比较简单的一个树形dp 我们令\(dp[i][0/1]\)表示是否\(i\)的子树,是否选\(i\)这个点的方案数. 一个比较显然的想法. \(dp[ ...
- 初学python-day3 列表
- 【UE4】读写 Texture 数据
创建texture 方式一 void AActor_Assignment2::TextureFromImage_Internal( const TArray<FColor>& Sr ...
- JuiceFS 如何帮助趣头条超大规模 HDFS 降负载
作者简介 王振华,趣头条大数据总监,趣头条大数据负责人. 王海胜,趣头条大数据工程师,10 年互联网工作经验,曾在 eBay.唯品会等公司从事大数据开发相关工作,有丰富的大数据落地经验. 高昌健,Ju ...