如何新建java内部类_java内部类-1(内部类的定义)

小胖从官网出发,研究下为什么我们需要些内部类,内部类的区别和联系。

思考三个问题:

(1)为什么需要内部类?静态内部类和非静态内部类有什么区别;

(2)为什么内部类可以无条件访问外部类成员;

(3)为什么jdk1.8之前,局部内部类和匿名内部类访问局部变量或者方法参数需要加final修饰符?

1. 官网阅读:

1.1 为什么需要内部类

It is a way of logically grouping classes that are only used in one place: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.

简化包配置:如果一个类只对另一个类有用,将他们嵌套在一起是合理的。嵌套一些“有帮助的类”可以使得包更加简化

It increases encapsulation: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.

增加了封装:两个顶级类A和B,B需要访问A中声明为private的成员。

It can lead to more readable and maintainable code: Nesting small classes within top-level classes places the code closer to where it is used.

易读和可维护:在顶级类中嵌套小类会使代码更接近于使用它的位置。

1.2 为什么Java内部类设计为静态和非静态

Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes.

嵌套类一般分为两类:静态和非静态。声明static的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。

A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

静态嵌套类就像任何顶级类一样 与 其外部类(其他的类)的实例成员交互。事实上,静态内部类在行为上就是一个顶级类,它嵌套在一个顶级类中以方便打包。

As with class methods and variables, a static nested class is associated with its outer class. And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference.

和静态方法一样,静态嵌套类不能直接引用封闭类中定义的实例变量和方法。只能通过对象的引用来使用它们。

静态方法引用对象:

public class TestNest {

private String abc;

public String getAbc() {

return abc;

}

public static String nestSta() {

TestNest testNest = new TestNest();

return testNest.getAbc();

}

}

As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.

内部类可以直接访问该对象的字段和方法,由于内部类和实例相关联,因此无法定义任何的静态成员变量。

那我们怎么理解呢?

静态内部类就是一个独立的类。为什么使用静态内部类呢?

比如A,B两个类,B有点特殊,虽然可以单独存在,但只能被A使用。那么此时应该怎么办?把B并入到A里面,复杂性提高,搞的A违反单一职责。如果B独立,又可以被其他类依赖,不符合设计本意,不如将其变成A.B。其他类就不能使用B了。

而相比起来,非静态的才是真正的内部类,对其外部类有一个引用。

1.3 序列化

Serialization of inner classes, including local and anonymous classes, is strongly discouraged. When the Java compiler compiles certain constructs, such as inner classes, it creates synthetic constructs;.....However, synthetic constructs can vary among different Java compiler implementations, which means that .class files can vary among different implementations as well. Consequently, you may have compatibility issues if you serialize an inner class and then deserialize it with a different JRE implementation.

强烈建议不要对内部类进行序列化。java编译器编译某些构造(如内部类)时,他会创建“合成构造”。合成构造在不同的java编译器中变化。序列化内部类,然后使用不同的JRE实现反序列化,则可能存在兼容的问题。

2. 实战内部类

2.1 成员内部类

类的成员 无条件访问外部类 依赖外部类 多种访问权限

2.1.1 内部类的特点

成员内部类中不能定义静态变量

public class Outer {

private String name;

public Outer(String name) {

this.name = name;

}

//外部类使用内部类的方法

public void write() {

Inner inner = new Inner();

inner.say();

System.out.println(inner.getInnnerName());

}

//成员内部类

class Inner {

private String InnnerName;

public String getInnnerName() {

return InnnerName;

}

public void setInnnerName(String innnerName) {

InnnerName = innnerName;

}

public void say() {

System.out.println(name);

}

}

}

成员内部类相当于类的成员变量,可以无条件访问外部类的成员。但不过要注意的是,成员内部类和外部内部类拥有同名的成员方法或者方法时,要显式的声明,否则默认情况下访问的是内部类成员。

外部类.this.成员变量

外部类.this.成员方法

反编译后的class文件:

public class Outer {

private String name;

public Outer(String name) {

this.name = name;

}

public void write() {

Outer.Inner inner = new Outer.Inner();

inner.say();

System.out.println(inner.getInnnerName());

}

class Inner {

private String InnnerName;

Inner() {

}

public String getInnnerName() {

return this.InnnerName;

}

public void setInnnerName(String innnerName) {

this.InnnerName = innnerName;

}

public void say() {

System.out.println(Outer.this.name);

}

}

}

外部类想访问内部类的成员必须先创建一个内部类的对象,再通过指向这个对象的引用来访问。

public void wirte() {

Inner inner = new Inner();

inner.say();

System.out.println(i + ":" + name);

}

于是外部类就可以访问内部类的所有成员了!

2.1.2 如何创建内部类

我们知道,成员内部类是依赖于外部类而存在的。也就是说,想要创建成员内部类,前提是有一个外部类对象。

方式一:

Outer outer = new Outer();

Inner inner = outer.new Inner();

方式二:

Outter.Inner inner1 = outter.getInnerInstance();

//getInnerInstance()方法

public Inner getInnerInstance() {

if(inner == null)

inner = new Inner();

return inner;

}

2.1.3 成员内部类权限问题

成员内部类可以拥有public、default、protected、private权限。

private只能在外部类中被访问。

default同一个包下访问。

protected同一个包下或继承外部类的情况下。

public任何地方。

而外部类只有public和default两种访问权限。

2.1.4 小结

成员内部类是依附于外部类存在的,并且和外部类的一个成员变量有相似之处。内部类可以无条件访问外部类的成员、外部类需要内部类的引用才能访问、四种访问权限。

请注意(下面两个内部类):jdk版本是1.8,看起来似乎编译器取消了没有声明为final的变量或参数也可以在局部内部类和匿名内部类被访问。但事实上是Java8引入了effectively final概念,被默认成为了final类型。

2.2 局部内部类

方法或作用域内 局部变量

注意:局部内部类和成员内部类的区别就是局部内部类的访问仅限于方法内或者该作用域内。不能定义静态变量。

class Outer {

Object method() {

int locvar = 1;

System.out.println("1111");

class Inner {

void displayLocvar() {

System.out.println("locvar = " + locvar);

}

}

Object in = new Inner();

return in;

}

}

注意:局部内部类更像一个局部变量,是没有访问修饰符的。

2.3 匿名内部类

一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承的方法的实现或者重写。

匿名类的格式:

new Thread(new Runnable() {

@Override

public void run() {

//TODO

}

});

通过new XXX(){};的方式创建了一个只能使用一次子类。

--

为什么叫做匿名内部类呢?

匿名内部类只能使用一次。他通常用来简化代码。但是使用匿名内部类还有一个前提条件:必须继承一个父类(抽象类或具体类)或是实现一个接口。

对于这个问题,首先我们应该明确的一点是对于匿名内部类,它可能引用三种外部变量:

外部类的成员变量(所有的变量);

外部方法或作用域内的局部变量;

外部方法的参数;

实际上,只有第一种变量不需要声明为final。

原因:

首先,在这里提出,网上的答案基本是:局部变量声明周期和局部类的声明周期不同。会导致内部类失去引用造成错误!!!等等,一个变量加上final就可以延长生命周期了吗?那加上final岂不是会造成内存短暂泄露?

正解:匿名内部类和所有类一样,也是有自己的构造函数的,只不过这个构造函数是隐式的。

加入final修饰符是为了保持内部和外部的数据的一致性。

编译前:

public class Outer {

String string = "";

void outerTest(final char ch){

final Integer integer = 1;

Inner inner = new Inner() {

void innerTest() {

System.out.println(string);

System.out.println(ch);

System.out.println(integer);

}

};

}

public static void main(String[] args) {

new Outer().outerTest(' ');

}

class Inner {

}

}

编译后:

class Outer$1extends Outer.Inner

{

Outer$1(Outer paramOuter, char paramChar, Integer paramInteger)

{

super(paramOuter);

}

void innerTest()

{

System.out.println(this.this$0.string);

System.out.println(this.val$ch);

System.out.println(this.val$integer);

}

}

匿名内部类之所以可以访问局部变量,是因为在底层将这个局部变量的值传入了匿名内部类中,并且以匿名内部类的成员变量存在,这个值的传递过程是通过匿名内部类的构造器完成的。

我们可以看到匿名内部类引用的局部变量和方法参数以及外部类的引用都会被当做构造函数的参数。但是外部类的成员变量是通过外部类的引用来访问的。

那么为什么匿名内部类访问外部类的成员变量,无需final修饰呢?

因为非静态内部类的对象保存了外部类对象的引用,因此内部类对外部类成员变量的修改都会真实的反应到外部类实例本身,所以不需要final修饰。

需要引入两个知识点:

值传递和引用传递:基本类型作为参数传递时,传递的是值的引用,无论怎么改变这个拷贝,原值是不会改变的;当对象作为参数传递时,传递是对象引用的拷贝,无论怎么改变新引用的指向,原引用是不会改变的(当然通过新引用改变对象的内容,那么改变就是确确实实发生了)。

final作用:被final修饰基本类型变量,不可更改其值;当被final修饰引用变量,不可改变其指向,只能改变对象的内容。

于是,假设允许不对局部变量加final,当匿名内部类里面尝试改变外部基本类型的值的时候,或者改变外部引用变量的指向的时候,表面上看起来是成功了,但是实际上并不会影响到外部的变量。

所以java就一刀切,强制加上了final修饰。

2.4 静态内部类

我们上面知道,静态内部类是一个独立的类,不需要依赖外部类也能存在的。所以静态内部类不能使用外部类非static成员变量或者方法。因为外部类的非静态成员必须依附于具体的对象。

624aacbdf9ce?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

静态内部类

静态内部类的创建方法:

外部类.内部类 引用名=new 外部类.内部类();

public static void main(String[] args) {

//静态内部类的创建方法:

Outer.Inner in = new Outer.Inner();

in.say();

}

3. 问题解答

看到这里,我相信大家应该心里对问题也有了自己的答案。

静态内部类是不依附与外部类存在的。而非静态内部类就是外部类的一个成员,是需要依附于外部类。

非静态内部类中含有构造函数,构造函数中会将外部类的引用传入,所以,内部类可以无条件访问外部类成员。

为什么使用final和生命周期是无关的,主要是java为了保持内部和外部变量的统一。

4. 内部类常见面试题

根据注释填写(1),(2),(3)处的代码

public class Test{

public static void main(String[] args){

// 初始化Bean1

(1)

bean1.I++;

// 初始化Bean2

(2)

bean2.J++;

//初始化Bean3

(3)

bean3.k++;

}

class Bean1{

public int I = 0;

}

static class Bean2{

public int J = 0;

}

}

class Bean{

class Bean3{

public int k = 0;

}

}

我们可以知道,成员内部类,必须先产生外部类的实例化对象,才能产生内部类的实例化对象。而静态内部类不需要产生实例化对象即可产生内部类的实例化对象。

创建静态内部类:

外部类类名.内部类类名 xxx=new 外部类类名.内部类类名();

创建成员内部类:

外部类类名.内部类类名 xxx=外部类对象名.new 内部类类名();

因此,(1),(2),(3)处的代码分别为:

Test test = new Test();

Test.Bean1 bean1 = test.new Bean1();

Test.Bean2 b2 = new Test.Bean2();

Bean bean = new Bean();

Bean.Bean3 bean3 = bean.new Bean3();

2.下面这段代码的输出结果是什么?

public class Test {

public static void main(String[] args) {

Outter outter = new Outter();

outter.new Inner().print();

}

}

class Outter

{

private int a = 1;

class Inner {

private int a = 2;

public void print() {

int a = 3;

System.out.println("局部变量:" + a);

System.out.println("内部类变量:" + this.a);

System.out.println("外部类变量:" + Outter.this.a);

}

}

}

输出答案

3 2 1

总结:内部类和外部类变量的访问权限问题:

非静态内部类依赖于外部类对象的创建,所以,非静态类中不能定义静态变量。

非静态内部类的构造方法中,含有外部类的引用。可以直接使用所有的外部类成员。

外部类不能直接使用非静态内部类的成员。除非创建内部类对象。

可以把静态内部类看做一个独立的静态类,所以不能直接使用一个类的实例成员。

匿名类必须继承一个类(抽象类或具体类)或者实现一个接口。new XXX(){};就是一个内部类。

只含有private构造方法的类不能被继承,所以可以使用protected修饰类,以达到让子类继承的目的,此时,使用匿名内部类的new XXX(){};的方式就可以创建出一个XXX的子类对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/512168.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

stack vs heap:栈区分配内存快还是堆区分配内存快 ?

作者 | 码农的荒岛求生来源 | 码农的荒岛求生有伙伴问到底是从栈上分配内存快还是从堆上分配内存快,这是个比较基础的问题,今天就来聊一聊。栈区的内存申请与释放毫无疑问,显然从栈上分配内存更快,因为从栈上分配内存仅仅就是栈指…

CDP 平台简介

简介: EDC 建立在 Cloudera Data Platform(CDP) 之上,该产品结合了 Cloudera Enterprise Data Hub 和 Hortonworks Data Platform Enterprise 的优点,并在技术堆栈中增加了新功能和对已有技术提供了增强功能。这种统一的发行是一个可扩展且可…

400倍加速, PolarDB HTAP实时数据分析技术解密

简介: PolarDB MySQL是因云而生的一个数据库系统, 除了云上OLTP场景,大量客户也对PolarDB提出了实时数据分析的性能需求。对此PolarDB技术团队提出了In-Memory Column Index(IMCI)的技术方案,在复杂分析查询场景获得的数百倍的加速…

建立数字化、学习型人事平台,HR 与业务终于不再「隔空对话」

本篇文章暨 CSDN《中国 101 计划》系列数字化转型场景之一。 《中国 101 计划——探索企业数字化发展新生态》为 CSDN 联合《新程序员》、GitCode.net 开源代码仓共同策划推出的系列活动,寻访一百零一个数字化转型场景,聚合呈现并开通评选通道&#xff…

OpenYurt 深度解读|开启边缘设备的云原生管理能力

简介: 北京时间 9 月 27 号,OpenYurt 发布 v0.5.0 版本。新发布版本中首次提出 kubernetes-native非侵入、可扩展的边缘设备管理标准,使 Kubernetes 业务负载模型和 IOT 设备管理模型无缝融合。 作者|贾燚星(VMware), 何淋波(阿里…

Cloudera Manager 术语和架构

简介: 本文介绍了Cloudera Manager 的常见术语和架构 Cloudera Manager 术语 为了有效地使用Cloudera Manager,您应该首先了解其术语。 术语之间的关系如下所示,其定义如下: 有时,术语服务和角色用于同时指代类型和…

冬奥网络安全卫士被表彰突出贡献,探寻冬奥背后的安全竞技

奥运史上首次公开招募白帽子担任“冬奥网络安全卫士”。 据统计,从冬奥会开始到冬残奥会闭幕式结束,奇安信共检测日志数量累积超1850亿,日均检测日志超37亿,累计发现修复漏洞约5800个,发现恶意样本54个,排查…

打破 Serverless 落地边界,阿里云 SAE 发布 5 大新特性

简介: SAE 的 5 大新特性、4 大最佳实践,打破了 Serverless 落地的边界,让 All on Serverless 成为可能. 微服务场景,开源自建真的最快最省最稳的?复杂性真的会成为 Kubernetes 的“致命伤”吗?企业应用容…

java线程一定是thread_深入理解Java多线程(multiThread)

多线程的基本概念一个java程序启动后,默认只有一个主线程(Main Thread)。如果我们要使用主线程同时执行某一件事,那么该怎么操作呢?例如,在一个窗口中,同时画两排圆,一排在10像素的高度,一排在5…

技术解读|云上企业级存储——打开存储新维度,促进用户核心业务创新

简介: 将企业级存储和云的特点进行完美的融合是云上企业级存储的目标,它打开存储更多新的维度,在保障用户业务永续的同时,帮助用户更好的进行业务创新。本文属ESSD技术解读的总篇,总体介绍ESSD 云盘创新融合了云和企业…

金蝶发布2021年财报:云业务同比增44.2%,继续加码研发技术创新

编辑 | 宋慧 出品 | CSDN云计算 金蝶国际软件集团有限公司(“金蝶国际”、“金蝶”或“公司”,连同其附属公司统称“集团”;股份编号:0268.HK)今日公布其截至2021年12月31日止十二个月(“报告期”&#xf…

分布式系统一致性测试框架Jepsen在女娲的实践应用

简介: 女娲团队在过去大半年时间里持续投入女娲2.0研发,将一致性引擎和业务状态机解耦,一致性引擎可支持Paxos、Raft、EPaxos等多种一致性协议,根据业务需求支撑不同的业务状态机。其中的一致性引擎模块是关键,研发一致…

“预习-上课-复习”:达摩院类人学习新范式探索

简介: 预习时关注重点,上课时由易到难,复习时举一反三,能否让机器也按照“预习-上课-复习”的学习范式进行学习呢? 达摩院对话智能(Conversational AI)团队对这个问题进行了研究探索&#xff0c…

云上虚拟IDC(私有池)如何为客户业务的确定性、连续性保驾护航

简介: 企业业务上云后,还面临特定可用区购买云上特定计算产品实例失败的困境?云上私有池pick一下 Why 云上业务为什么需要资源确定性、服务连续性 云计算正朝着像水电煤一样的基础设施演进,支持用户按需使用、按量付费。目前&am…

java中img属性_如果html img的src属性无效,请输入默认图像?

回答(19)2 years ago你问过一个只有HTML的解决方案....../p>"http://www.w3.org/TR/html4/strict.dtd">Object Test由于第一个图像没有使用不支持object的旧浏览器,因此它将忽略该标记并使用 img 标记 . 有关兼容性,请参见caniuse网站 .…

阿里云日志服务SLS,打造云原生时代智能运维

2021年10月21日,阿里云针对企业运维难题,在云栖大会为大家带来了一场《智能运维论坛》的主题演讲。在会上,阿里云资深技术专家、日志服务技术负责人简志提出“云原生时代,企业业务数字化是对工程师们严峻的挑战。作为运维工程师&a…

实践分享丨企业上云后资源容量如何规划和实施

简介: 企业上云后,云上的预算直接影响上云的优先级、进度、深度。预算投入的多少,与业务发展和资源需求的容量评估紧密相关。精准的容量评估,可以使企业上云的预算规划更科学,同时也更贴合业务发展阶段的需要。本文分享…

如果让你来设计网络

作者 | 闪客sun 来源 | 低并发编程 你是一台电脑,你的名字叫 A 很久很久之前,你不与任何其他电脑相连接,孤苦伶仃。 直到有一天,你希望与另一台电脑 B 建立通信,于是你们各开了一个网口,用一根网线连接了起…

【ESSD技术解读-01】 云原生时代,阿里云 ESSD 快照服务 助力企业级数据保护

简介:本文以云原生为时代背景,介绍了阿里云块存储快照服务如何基于高性能 ESSD 云盘提升快照服务性能,提供轻量、实时的用户体验及揭秘背后的技术原理。依据行业发展及云上数据保护场景,为企业用户及备份厂商提供基于快照高级特性…

又居家办公了,要签合同怎么办?

作者 | CSDN 来源 | CSDN云计算 本篇文章暨 CSDN《中国 101 计划》系列数字化转型场景之一。 《中国 101 计划——探索企业数字化发展新生态》为 CSDN 联合《新程序员》、GitCode.net 开源代码仓共同策划推出的系列活动,寻访一百零一个数字化转型场景,聚…