序言

有位小同学要我写一篇这个的总结,我说那好吧,那就动手写总结一下这个内部类的知识,感觉这个在面试中也会经常遇到,内部类、反射、集合、IO流、异常、多线程、泛型这些重要的基础知识大家都比较容易记不住。大概是自己平常用的比较少,所以经常性的会忘记,现在通过博文的方式记录下来,以后忘记可以回过头来自己看。

--WZY

一、什么是内部类

顾名思义,内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。

在一个类中有很多属性,比如、成员变量,成员方法,局部变量,静态方法等(这些区别应该知道把,如果不知道的应该先把这几个弄清楚,然后在继续往下看,对,说的就是你),那么这样一比较,B类在A类中的不同位置就可以被分为了不同的内部类了。总共有四种,

1、成员内部类

2、局部内部类

3、静态内部类

4、匿名内部类

现在看的一脸懵逼没关系,接下来我会一一讲解这四种内部类和用法及区别

二、成员内部类

1、什么是成员内部类?

例如:  Outer类中有一个私有的成员变量id、还有一个out方法。 在内部类Inner中只有一个in方法   (注明:写的类中没有具体意义,就是为了说明问题而写的)

//在A类中申明了一个B类,此B类就在A的内部,并且在成员变量的位置上,所以就称为成员内部类

public classOuter {private intid;public voidout(){

System.out.println("这是外部类方法");

}classInner{public voidin(){

System.out.println("这是内部类方法");

}

}

}

2、如何实例化成员内部类呢?

public classOuter {private intid;public voidout(){

System.out.println("这是外部类方法");

}classInner{public voidin(){

System.out.println("这是内部类方法");

}

}

}----------------------------------------------------------------

public classTest{

public static void main(String[] args) {

//实例化成员内部类分两步

//1、实例化外部类

Outer outObject = new Outer();

//2、通过外部类调用内部类

Outer.Inner inObject = outObject.new Inner();

//测试,调用内部类中的方法

inObject.in();//打印:这是内部类方法

}

}

分析:这个由外部类创建内部类对象不难理解把,想想如果你要使用一个类中方法或者属性,你就必须要先有该类的一个对象,同理,一个类在另一个类的内部,那么想要使用这个内部类,就必须先要有外部类的一个实例对象,然后在通过该对象去使用内部类。

3、成员内部类能做哪些事情?

·访问外部类的所有属性(这里的属性包括私有的成员变量,方法),例子大多数还是上面的内容,稍微改变一点点

public classOuter {private intid;public voidout(){

System.out.println("这是外部类方法");

}classInner{public voidin(){

System.out.println("这是内部类方法");

}

//内部类访问外部类私有的成员变量

public void useId(){

System.out.println(id+3);。

}

//内部类访问外部类的方法

public void useOut(){

out();

}

}

}

--------------------------------------------------

public classTest{

public static void main(String[] args) {

//实例化成员内部类分两步

//1、实例化外部类

Outer outObject = new Outer();

//2、通过外部类调用内部类

Outer.Inner inObject = outObject.new Inner();

//测试

inObject.useId();//打印3,因为id初始化值为0,0+3就为3,其中在内部类就使用了外部类的私有成员变量id。

inObject.useOut();//打印:这是外部类方法

}

}

如果内部类中的变量名和外部类的成员变量名一样,那么如何会怎么样呢?

public classOuter {private intid;//默认初始化0public voidout(){

System.out.println("这是外部类方法");

}classInner{private int id=8; //这个id跟外部类的属性id名称一样。

public voidin(){

System.out.println("这是内部类方法");

}public voidtest(){

System.out.println(id);//输出8,内部类中的变量会暂时将外部类的成员变量给隐藏//如何调用外部类的成员变量呢?通过Outer.this,想要知道为什么能通过这个来调用,就得明白下面这个原理//想实例化内部类对象,就必须通过外部类对象,当外部类对象来new出内部类对象时,会//把自己(外部类对象)的引用传到了内部类中,所以内部类就可以通过Outer.this来访问外部类的属性和方法,到这里,你也就可以知道为什么内部类可以访问外部类的属性和方法,这里由于有两个相同的

属性名称,所以需要显示的用Outer.this来调用外部类的属性,平常如果属性名不重复,那么我们在内部类中调用外部类的属性和方法时,前面就隐式的调用了Outer.this。

System.out.println(Outer.this.id);//输出外部类的属性id。也就是输出0

}

}

}

借助成员内部类,来总结内部类(包括4种内部类)的通用用法:

1、要想访问内部类中的内容,必须通过外部类对象来实例化内部类。

2、能够访问外部类所有的属性和方法,原理就是在通过外部类对象实例化内部类对象时,外部类对象把自己的引用传进了内部类,使内部类可以用通过Outer.this去调用外部类的属性和方法,一般都是隐式调用了,但是当内部类中有属性或者方法名和外部类中的属性或方法名相同的时候,就需要通过显式调用Outer.this了。

4、成员内部类的面试题

//要求:使用已知的变量,在控制台输出30,20,10。

classOuter {public int num = 10;classInner {public int num = 20;public voidshow() {int num = 30;

System.out.println(?);

System.out.println(??);

System.out.println(???);

}

}

}classInnerClassTest {public static voidmain(String[] args) {

Outer.Inner oi= new Outer().newInner();

oi.show();

}

}

答案:num、this.num、Outer.this.num

解析:这题你如何明白了上面总结中的第二点,那么非常简单,考察的就是1、局部变量 2、this,和3、Outer.this,也就是内部类访问外部类属性方法的原理。这考察三个东西,

1、在一个方法中,使用直接使用变量名,肯定使用的是局部变量,因为会把大的成员变量给隐藏掉,这题中,也就是说show方法中的num会将内部类中的成员变量num隐藏掉,而内部类中的成员变量num又会把外部类中的成员变量num隐藏掉,所以通过直接输出num,会是show方法中的局部变量的值30.

2、使用this.num调用,其this代表的是调用该方法的对象,调用show方法的是oi,oi也就是内部类对象,所以oi.num也就标识内部类的成员变量num的值20

3、Outer.this.num,调用的外部类中的成员变量num的值也就是10,这个如果不清楚就看上面总结中的第二点,就是那个原理。

三、局部内部类

1、什么是局部内部类,跟局部变量一样,在一个方法中定义的,那么就是局部内部类了。

例如

public classOuter {private intid;

//在method01方法中有一个Inner内部类,这个内部类就称为局部内部类public voidmethod01(){classInner{public voidin(){

System.out.println("这是局部内部类");

}}

}

}

2、局部内部类一般的作用跟在成员内部类中总结的差不多,但是有两个要注意的地方,

1、在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰。看例子

为什么需要使用final?

final修饰变量:变为常量,会在常量池中放着,

逆向思维想这个问题,如果不实用final修饰,当局部内部类被实例化后,方法弹栈,局部变量随着跟着消失,这个时候局部内部类对象在想去调用该局部变量,就会报错,因为该局部变量已经没了,当局部变量用fanal修饰后,就会将其加入常量池中,即使方法弹栈了,该局部变量还在常量池中呆着,局部内部类也就是够调用。所以局部内部类想要调用局部变量时,需要使用final修饰,不使用,编译度通不过。

public classOuter {private intid;public voidmethod01(){final int cid = 3; //这个就是局部变量cid。要让局部内部类使用,就得变为final并且赋值,如果不使用final修饰,就会报错

classInner{//内部类的第一个方法

public voidin(){

System.out.println("这是局部内部类");

}//内部类中的使用局部变量cid的方法

public voiduseCid(){

System.out.println(cid);

}

}

}

}

2、局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。看下面例子就知道如何用了

public classOuter {private intid;public voidout(){

System.out.println("外部类方法");

}public voidmethod01(){classInner{public voidin(){

System.out.println("这是局部内部类");

}

}

//关键在这里,如需要在method01方法中自己创建内部类实例,然后调用内部类中的方法,等待外部类调用method01方法,就可以执行到内部类中的方法了。

Inner In= newInner();

In.in();

}

}

总结:局部内部类就只要注意那亮点就行了

1、在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰

2、如何调用局部内部类方法。

四、静态内部类

根据名字就知道,使用static修饰的内部类,就叫做静态内部类了。

回顾static的用法:一般只修饰变量和方法,平常不可以修饰类,但是内部类却可以被static修饰。

1、static修饰成员变量:整个类的实例共享静态变量

2、static修饰方法:静态方法,只能够访问用static修饰的属性或方法,而非静态方法可以访问static修饰的方法或属性

3、被static修饰了的成员变量和方法能直接被类名调用。

4、static不能修饰局部变量,切记,不要搞混淆了,static平常就用来修饰成员变量和方法。

注意:

1、我们上面说的内部类能够调用外部类的方法和属性,在静态内部类中就行了,因为静态内部类没有了指向外部类对象的引用。除非外部类中的方法或者属性也是静态的。这就回归到了static关键字的用法。

2、静态内部类能够直接被外部类给实例化,不需要使用外部类对象

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

3、静态内部类中可以什么静态方法和静态变量,但是非静态内部类中就不可以申明静态方法和静态变量

五、匿名内部类

这个在四种内部类中,使用的是最多的,在以后遇到的程序中,大多数出现的也就是它。

什么是匿名对象?如果一个对象只要使用一次,那么我们就是需要new Object().method()。 就可以了,而不需要给这个实例保存到该类型变量中去。这就是匿名对象。例如

public classTest {public static voidmain(String[] args) {//讲new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写

Apple apple = newApple();

apple.eat();//这种就叫做匿名对象的使用,不把实例保存到变量中。

newApple().eat();

}

}classApple{public voideat(){

System.out.println("我要被吃了");

}

}

匿名内部类跟匿名对象是一个道理,

匿名对象:我只需要用一次,那么我就不用声明一个该类型变量来保存对象了,

匿名内部类:我也只需要用一次,那我就不需要在类中先定义一个内部类,而是等待需要用的时候,我就在临时实现这个内部类,因为用次数少,可能就这一次,那么这样写内部类,更方便。不然先写出一个内部类的全部实现来,然后就调用它一次,岂不是用完之后就一直将其放在那,那就没必要那样。

匿名内部类是如何个格式呢?

前提:存在一个类或者接口

为什么呢?

例如:A接口  new A(){};  必须实现A接口中所有抽象方法,实现完之后,new A(){} 这个整体就是A的一个匿名实现类对象,肯定可以调用自己类中的方法

不一定是接口,可以是抽象类,也可以是完整的类,如果是抽象类的话,跟接口一样,实现抽象的方法,如果是完整的类,就可以重写自己所需要的方法,然后在调用,

举个例子,看看不使用匿名内部类和使用了匿名内部类的区别

不实用匿名内部类,真麻烦啊。

public class Test {

public static void main(String[] args) {

//如果我们需要使用接口中的方法,我们就需要走3步,1、实现接口 2、创建实现接口类的实例对象 3、通过对象调用方法

//第二步

Test02 test = new Test02();

//第三步

test.method();

}

}

//接口Test1

interface Test01{

public void method();

}

//第一步、实现Test01接口

class Test02 implements Test01{

@Override

public void method() {

System.out.println("实现了Test接口的方法");

}

}

使用了匿名内部类。

public classTest {public static voidmain(String[] args) {

//如果我们需要使用接口中的方法,我们只需要走一步,就是使用匿名内部类,直接将其类的对象创建出来。

new Test1(){

public void method(){

System.out.println("实现了Test接口的方法");

}

}.method();

}

}interfaceTest1{public voidmethod();

}

解析:其实只要明白一点,new Test1(){实现接口中方法的代码};  Test1(){...}这个的作用就是将接口给实现了,只不过这里实现该接口的是一个匿名类,也就是说这个类没名字,只能使用这一次,我们知道了这是一个类, 将其new出来,就能获得一个实现了Test1接口的类的实例对象,通过该实例对象,就能调用该类中的方法了,因为其匿名类是在一个类中实现的,所以叫其匿名内部类,不要纠结为什么Test1(){...}就相当于实现了Test1接口,这其中的原理等足够强大了,在去学习,不要钻牛角尖,这里就仅仅是需要知道他的作用是什么,做了些什么东西就行。

匿名内部类的面试题:

*A:面试题*按照要求,补齐代码interface Inter { voidshow(); }class Outer { //补齐代码 }

classOuterDemo {public static voidmain(String[] args) {

Outer.method().show();

}

}

要求在控制台输出”HelloWorld”

答案:

* A:面试题

*

按照要求,补齐代码

interface Inter { void show(); }

class Outer {

//补齐代码

public static Inter method(){

return new Inter(){

void show(){

System.out.println("HelloWorld");

}

};

}

}

class OuterDemo {

public static void main(String[] args) {

Outer.method().show();

}

}

要求在控制台输出”HelloWorld”

解析:这个题目挺有趣的,考了很多东西,一开始只能说我自己度懵逼了,是一个局部匿名内部类。  通过看主方法中的调用,Outer.method(),能直接用类名调用方法,那么肯定该方法就是一个static方法,然后又直接调用了show()方法,说明这个method方法有一个返回值,其返回值类型就是实现该接口类的类型,因为只有接口中有show()这个方法。所以在method中就是一个匿名内部类。

java 如何实例化内部类_java之内部类详解相关推荐

  1. java反射源码_java反射技术详解附源码

    在学校学习Java时,由于学的不扎实,也没经历过太多实战项目,所以很多重要的知识点瞟一眼就过去了,比如现在要讲的反射,当时直接就忽略掉了,可现在发现很多地方需要反射,不得不重新学习一下,上学欠了太多债 ...

  2. java配置文件实现方式_java相关:详解Spring加载Properties配置文件的四种方式

    java相关:详解Spring加载Properties配置文件的四种方式 发布于 2020-4-29| 复制链接 摘记: 一.通过 context:property-placeholder 标签实现配 ...

  3. java获取枚举索引_Java枚举使用详解

    在实际编程中,往往存在着这样的"数据集",它们的数值在程序中是稳定的,而且"数据集"中的元素是有限的. 例如星期一到星期日七个数据元素组成了一周的"数 ...

  4. java for新循环_Java for循环详解

    Java for循环详解 for 语句是应用最广泛.功能最强的一种循环语句.大部分情况下,for 循环可以代替 while 循环.do while 循环. for 语句是一种在程序执行前就要先判断条件 ...

  5. 基于java洗浴中心管理系统_Java IO流详解

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  6. java的scanner用法_Java Scanner用法详解

    一.Scanner类简介 Java 5添加了java.util.Scanner类,这是一个用于扫描输入文本的新的实用程序.它是以前的StringTokenizer和Matcher类之间的某种结合.由于 ...

  7. java lock代码写法_java Lock接口详解及实例代码

    java  lock接口 java.util.concurrent.locks 接口lock public interface loce loce实现提供了比使用synchronized方法和语句可获 ...

  8. java 获取 网卡名称_Java获取网卡信息详解

    InterfaceAddress 类表示一个由名称和分配给此接口的 IP 地址列表组成的网络接口.它用于标识加入多播组的本地接口. 接口通常是按名称(如 "le0")区分的. Ne ...

  9. java程序日期转换_Java 日期转换详解及实例代码

    Java 日期转换 涉及的核心类:Date类.SimpleDateFormat类.Calendar类 一. Date型与long型 Date型转换为long型 Date date = new Date ...

最新文章

  1. 请填写红包接口调用ip_SOME/IP的车载网络应用
  2. Spring-Cloud 整合Nacos
  3. Foundry feats. MultiverseStudio
  4. Python中if name main的作用
  5. 机器学习笔记——感知机理解(自行取用,并不一定适合每个人)
  6. 数据挖掘 应用案例集
  7. Excel VBA 操作 Word(入门篇)
  8. RabbitMQ基础
  9. 科技爱好者周刊(第 167 期):广告拦截器太过分了
  10. 申请企业邮箱的好处,哪个企业邮箱好用?企业邮箱功能对比排行榜
  11. 2015年 网络工程师试卷答案及详解
  12. Windows 下网卡对802.1Q tag 的支持
  13. 爆笑!让你捧腹大笑的标语
  14. matlab信息隐藏图片,信息隐藏 实验二 BMP 图像信息隐藏
  15. 嵌入式C语言学习笔记附图
  16. 机器学习——使用array函数构建一维数组
  17. vue之push() pop() shift() unshift() splice() sort() reverse()等等
  18. Docker:网络模式详解
  19. Aid Learning更换壁纸
  20. 不能完成此操作, 因为发生意外错误(错误代码-51)

热门文章

  1. sqlserver 无法删除链接服务器,因为该服务器用作复制过程中的分发服务器
  2. ElasticSearch查询语法
  3. 运维人员的职业升级道路
  4. 法律网推荐(二) 用Pig进行数据预处理
  5. android adb 5037端口被占用解决方案
  6. Mac系统中Clion上实现伪的按任意键继续...
  7. Python 服务端编写
  8. JAVA正则表达式怎么表达汉字_Java的正则表达式匹配汉字
  9. mysql商品查询_mysql的查询、子查询及连接查询(商城查询常用)
  10. OC底层消息转发机制