java 内部类总结_java学习笔记9--内部类总结
java学习笔记系列:
java内部类分为: 非静态内部类、静态内部类、局部内部类、匿名内部类
内部类的共性:
(1)内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
(2)内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。
(3)内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。
java 中的内部类和接口加在一起,可以的解决常被 C++ 程序员抱怨 java 中存在的一个问题:没有多继承。实际上,C++ 的多继承设计起来很复杂,而 java 通过内部类加上接口,可以很好的实现多继承的效果。
非静态内部类
当一个类作为另一个类的非静态成员,则这个类就是一个非静态内部类。
创建非静态内部类是很容易的,只需要定义一个类让该类作为其他类的非静态成员。该非静态内部类和成员变量或者成员方法没有区别,同样可以在非静态内部类前面加可以修饰成员的修饰符。创建非静态内部类的基本语法如下所示:
classOutClass {classInClass {//内部类成员
}//外部类成员
}
在内部类的程序中,是经常会进行外部类和内部类之间访问的。在外部类中访问内部类是很容易的,只要把内部类看成一个类,然后创建该类的对象,使用对象来调用内部类中的成员就可以了。
在外部类中访问内部类的程序--举个例子:
classOutClass {class InClass { //创建非静态内部类
int i = 5; //内部类成员
}public void fun() { //外部类成员
InClass in = new InClass(); //创建一个内部类对象
int i = in.i; //访问内部类成员
System.out.println("InClass's var is: " +i);
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass out= newOutClass();
out.fun();
}
}
运行结果:
InClass's var is: 5
分析:在main方法中,首先创建一个外部类对象,然后访问外部类的成员方法。在外部类的成员方法中,创建了一个内部类对象,然后使用内部类对象调用内部类的成员变量,从而得到结果。编译该程序将产生三个class文件,分别是主类、外部类和内部类。内部类产生的class文件的名称为OutClass$InClass.class,在该名称中可以区分该内部类到底是哪一个类的内部类。
不但可以在外部类中访问内部类,还可以在外部类外访问内部类。在外部类外访问内部类的基本语法如下所示。
OutClass.InClass oi=new OutClass().new InClass();
使用该方法就能够创建一个内部类对象,使用该内部类对象就可以访问内部类的成员。该方法是不容易理解的,可以分为下面的两条语句:
Wai w=new Wai();
Wai.Nei wn=w.new Nei();
这样就很容易理解了。首先是创建一个外部类的对象,然后让该外部类对象调用创建一个内部类对象。
在外部类外访问内部类的程序--举个例子:
classOutClass {class InClass { //创建非静态内部类
int i = 5; //内部类成员
int j = 6;
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass.InClass oi1= new OutClass().newInClass();
OutClass ocClass= newOutClass();
OutClass.InClass oi2= ocClass.newInClass();
System.out.println("InClass's var i is: " +oi1.i);
System.out.println("InClass's var j is: " +oi1.j);
}
}
在示例代码中使用了两种方法来从外部类外访问内部类。在外部类外访问内部类时,是不能够直接创建内部类对象的,因为内部类只是外部类的一个成员。所以要想创建内部类对象,首先要创建外部类对象,然后以外部类对象为标识来创建内部类对象。
在内部类中访问外部类
在内部类中访问外部类,就像所有的同一个类中成员互相访问一样,这样是没有限制的,包括将成员声明为private私有的。
举个例子:
classOutClass {int i = 8; //外部类成员变量
class InClass { //创建非静态内部类
public voidfun() {
System.out.println("OutClass's var is: " +i);
}
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass oc= new OutClass(); //创建外部类对象
OutClass.InClass oi = oc.new InClass(); //创建内部类对象
oi.fun(); //调用内部类中的成员
}
}
在示例代码中,在内部类中定义了一个fun来访问外部类中的成员变量i。可以看到从内部类中访问外部类是非常容易的,不需要添加任何内容,就像成员方法间调用一样。如果外部类中也有一个成员变量i,得到的是内部类成员变量的值。下面通过示例代码解决这个问题:
classOutClass {int i = 8; //外部类成员变量
class InClass { //创建非静态内部类
int i = 9;
OutClass oc= newOutClass();public void fun() { //内部类成员
System.out.println("InClass's var is: " +i);
System.out.println("OutClass's var is: " +oc.i);
}
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass oc= new OutClass(); //创建外部类对象
OutClass.InClass ic = oc.new InClass(); //创建内部类对象
ic.fun(); //调用内部类中的成员
}
}
在本程序中先定义了一个外部类的成员变量,接着定义了一个内部类的成员变量,这两个成员变量的名称是相同的。而在内部直接访问时,将访问的是内部类的成员变量。要想访问外部类成员变量,就需要首先创建一个外部类对象,然后使用该对象调用外部类成员变量。
局部内部类
局部内部类的作用范围是和局部变量的作用范围相同的,只在局部中起作用,所以对局部内部类进行访问时,只能在该局部内部类的作用范围内。
举个例子:
classOutClass {public voidfun() {class InClass { //定义一个局部内部类
int i = 5; //局部内部类的成员变量
}
InClass ic= newInClass();
System.out.println("InClass's var is: " +ic.i);
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass oc= newOutClass();
oc.fun();
}
}
在本程序中定义了一个局部内部类,并进行了对该局部内部类的访问。对该内部类进行访问必须在该内部类所在的方法中通过创建内部类对象来进行访问。这是因为这里的内部类是作为局部成员的形式出现的,只能在它所在的方法中进行调用。
局部内部类中访问外部类成员变量
在局部内部类中访问外部类成员变量是很容易实现的,并不需要进行过多操作。在局部内部类中可以直接调用外部类的成员变量。
举个例子:
classOutClass {int i = 9; //定义一个外部类的成员变量
public voidfun() {class InClass { //定义一个局部内部类
public voidInfun() {
System.out.println("OutClass's var is: " + i); //访问外部类中的成员变量
}
}
InClass ic= new InClass(); //创建内部类对象
ic.Infun(); //调用内部类中的成员方法
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass oc= new OutClass(); //创建外部类对象
oc.fun(); //调用内部类中的成员
}
}
在示例代码中定义了一个局部内部类,在该局部内部类中定义了一个方法来访问外部类的成员变量。
在局部内部类中访问外部类的局部变量
和访问外部类的成员变量不同,在局部内部类中访问外部类中和局部内部类在同一局部的局部变量是不能够直接访问的。
举个例子(下面是一段错误的代码):
classOutClass {public voidOutFun() {int i = 9;classInClass {public voidInFun() {
System.out.println("OutClass's var is: " + i);//访问外部类的成员变量
}
}
InClass ic= new InClass(); //创建内部类对象
ic.InFun(); //调用内部类中的成员方法
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass oc= new OutClass(); //创建外部类对象
oc.OutFun(); //调用内部类中的成员
}
}
运行产生异常:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Cannot refer to a non-final variable i inside an inner class defined in a different method
运行该程序是会发生错误的,错误信息为“从内部类中访问局部变量i;需要被声明为最终类型”。在局部内部类中访问外部类的局部变量是不能够访问普通的局部变量的,必须将该局部变量声明为final。
静态方法中的局部内部类
局部内部类定义在非静态方法和静态方法中是不同的,在前面例子都是将局部内部类定义在非静态方法中,下面就来学习静态方法中定义局部内部类的情况。在静态方法中定义的局部内部类要想访问外部类中的成员,该成员必须是静态成员。
classOutClass {static int i = 4;public static void OutFun() { //外部类成员
classInClass {public voidInFun() {
System.out.println("OutClass's local var is: " +i);
}
}
InClass ic= newInClass();
ic.InFun();
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass.OutFun();
}
}
静态内部类
前面已经学习了非静态内部类,接下来就来学习什么是静态内部类。静态内部类就是在外部类中扮演一个静态成员的角色。创建静态内部类的形式和创建非静态内部类的形式很相似的,只是需要将该内部类使用static修饰成静态的形式。使用static修饰类,这在正常类中是不可能的。定义静态内部类的语法如下所示:
classOutClass {static classInClass {//内部类成员
}//外部类成员
}
在外部类中访问静态内部类
在外部类中访问静态内部类和在外部类中访问非静态内部类一样的,只需要从成员间访问的角度就可以考虑到这一点。举个例子:
classOutClass {static class InClass { //创建静态内部类
int i = 5; //内部类成员
}public void OutFun() { //外部类成员
InClass ic = new InClass(); //创建一个内部类对象
int ii = ic.i; //访问内部类成员
System.out.println("static InClass's var is: " +ii);
}
}public classjavatest {public static voidmain(String args[ ]) {
OutClass oc= new OutClass(); //创建外部类对象
oc.OutFun(); //调用内部类中的成员
}
}
在外部类中访问静态内部类和访问非静态内部类是相同的,但是在外部类中访问静态内部类和非静态内部类就不再相同。因为静态内部类是外部类的静态成员,静态成员是不需要外部类对象而存在的,所以在外部类外,对静态内部类进行访问时是不需要创建外部类对象的。
注意:因为静态内部类是外部类的静态成员,静态成员是不需要外部类对象而存在的,所以在外部类外,对静态内部类进行访问时是不需要创建外部类对象的。
匿名内部类
在所有的内部类中最难的就应该是匿名内部类。匿名内部类从名字上看就知道是没有类名的内部类。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
创建匿名内部类
在创建匿名内部类中将使用到继承父类或者实现接口的知识,匿名内部类是没有名字的,所以在创建匿名内部类时同时创建匿名内部类的对象。创建匿名内部类的语法格式如下:
newInFather() {//匿名内部类
};
在创建匿名内部类的语法中,InFather是匿名内部类继承的父类的类名,使用new同时创建了匿名内部类的对象。在匿名内部类中可以重写父类中的方法,也可以定义自己的方法。
实例1:不使用匿名内部类来实现抽象方法
abstract classPerson {public abstract voideat();
}class Child extendsPerson {public voideat() {
System.out.println("eat something");
}
}public classtest {public static voidmain(String[] args) {
Person p= newChild();
p.eat();
}
}
运行结果:
eat something
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用。但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类会很麻烦。这个时候就引入了匿名内部类
实例2:匿名内部类的基本实现
abstract classPerson {public abstract voideat();
}public classtest {public static voidmain(String[] args) {
Person p= newPerson() {public voideat() {
System.out.println("eat something");
}
};
p.eat();
}
}
运行结果:
eat something
可以看到,我们直接将抽象类Person中的方法在大括号中实现了,这样便可以省略一个类的书写,并且匿名内部类还能用于接口上
实例3:在接口上使用匿名内部类
interfacePerson {public voideat();
}public classtest {public static voidmain(String[] args) {
Person p= newPerson() {public voideat() {
System.out.println("eat something");
}
};
p.eat();
}
}
运行结果:
eat something
由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
实例4:Thread类的匿名内部类实现
public classtest {public static voidmain(String[] args) {
Thread t= newThread() {public voidrun() {for (int i = 1; i <= 5; i++) {
System.out.print(i+ " ");
}
}
};
t.start();
}
}
运行结果:
1 2 3 4 5
实例5:Runnable接口的匿名内部类实现
public classtest {public static voidmain(String[] args) {
Runnable r= newRunnable() {public voidrun() {for (int i = 1; i <= 5; i++) {
System.out.print(i+ " ");
}
}
};
Thread t= newThread(r);
t.start();
}
}
运行结果:
1 2 3 4 5
参考资料:
java 内部类总结_java学习笔记9--内部类总结相关推荐
- java 调用弗雷_JAVA 学习笔记
封装: 将类的某些信息隐藏在类的内部,不允许外部程序访问,而是通过该类提供的方法实现对隐藏信息的操作和访问,保证了数据的安全性.(可以隐藏类的细节,方便修改) 封装的实现步骤: 1.修改属性的可见性: ...
- java 类可见性_Java学习笔记(类的可见性)
1)类的可见性:public;友好的(无关键字);protected;private; public:公开类,在包内,包外都可见,是可见性级别最高的; 友好的:也是默认的安全级别,包外不可见,包内可见 ...
- java程序伪代码_Java学习笔记——伪代码及程序控制
开学刚刚一个月,学习Java也已经有三周. 老师给了下面的实验题目: 某教师需要一个学生成绩计算应用程序.每个学生总评成绩是由平时成绩.期中成绩.期末成绩 和其它成绩组成,其所占比例为:平时成绩30% ...
- java 字符串赋值_Java 学习笔记(二)变量
标识符 标识符就是名字.类名,变量名,方法名,参数名等 标识符的命名规则 以字母.下划线或美元符号$开头,不能以数字开头 其后可以是字母.数组或美元符号$ 区分大小写 避免使用关键字 ...
- java日期类型_Java 学习笔记 (三) Java 日期类型
以下内容摘自: https://www.cnblogs.com/crazylqy/p/4172324.html import java.sql.Timestamp; import java.text ...
- JAVA翻译官_Java学习笔记之——Java介绍
1.Java体系: JavaSE:标准版,其他两个体系的基础 JavaEE:企业版 JavaME:微型版,适用于消费类型的微型设备 2.Java三大特性:封装.继承.多态 3.Java的特点:面向对象 ...
- java jcf查看_Java学习笔记——JCF集合框架
List基本使用 特别是有顺序,所有可以用get(i)读取出来 public static void main(String[] args) { //1.List基本使用 List lst = new ...
- java嵌套循环语句_Java学习笔记(七) 循环语句
一.for循环语句 1.1 循环结构 循环结构的组成: 初始语句:用于表示循环开启的起始状态,简单说就是循环开始的时候什么样 条件判断语句:用于表示循环反复执行的条件,简单说就是判断循环是否能一直执行 ...
- java 静态成员 创建_Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序...
当创建一个对象时,各种成员变量及构造方法的初始化或调用顺序是怎样的呢? (1).如果类尚未加载,则先初始化静态成员变量和静态代码块,再初始化成员变量,最后调用相应的构造方法: (2).如果类已经加载过 ...
- java算法优化_Java学习笔记---Java简单的代码算法优化(例)
例:用一张1元纸币兑换1分.2分.5分硬币,要求兑换50枚硬币,求出所有组合. package mypackage01; public class demo { public static void ...
最新文章
- ubuntu15.04 TLS
- 网站权重增加需要做的
- js实现随机选取[10,100)中的10个整数,存入一个数组,并排序。 另考虑(10,100]和[10,100]两种情况。...
- 工业控制软件测试评价体系,工业控制信息安全产品测试评价的体系.doc
- Realm Configuration HOW-TO--官方
- [Elixir008]Nested Module里的动态函数调用方式
- linux ctrlc 退出循环_linux按行读取 (while read line与forloop)
- sqlserver复习总结
- 我的Google Adsense帐户被关
- C++学习基础篇 —— 引用()的用法和应用
- [react] Consumer向上找不到Provider的时候怎么办?
- mysql mtop 使用_MYSQLMTOP监控环境搭建
- bzoj 1419: Red is good
- ubuntu之安装显卡驱动
- CCF NOI1001 温度转换
- python下载哪个版本好-究竟哪个版本的Python是最快的?
- bcm94352屏蔽第20针脚图_10核20线程的性能怪兽 十代酷睿首发评测
- We‘re sorry but XX doesn‘t work properly without JavaScript enabled. Please enable it to continue
- 某些网页页面偏左,什么原因?
- linux 用户配额设置,Linux如何设置磁盘配额