java的内部类和外部类用法讲解
作者:雪季28 发布时间:2022-10-18 21:14:41
一、为何使用内部类
内部类提供了更好的封装,只有外部类能访问内部类
内部类可以独立继承一个接口,不受外部类是否继承接口影响
内部类中的属性和方法即使是外部类也不能直接访问,相反内部类可以直接访问外部类的属性和方法,即使private
利于回调函数的编写
一个内部类的例子:
public class OuterClass {
private String outerName;
private int outerAge;
public class InnerClass{
private String innerName;
private int innerAge;
}
}
二、内部类与外部类的联系
2.1 内部类是一个相对独立的实体,与外部类不是is-a关系
内部类是一个编译时概念,编译后外部类及其内部类会生成两个独立的class文件: OuterClass.class和OuterClass$InnerClass.class,我用javac编译器对上面的OuterClass进行编译:
D:\>javac OuterClass.class
编译后的结果:
2.2 内部类可以直接访问外部类的元素,但是外部类不可以直接访问内部类的元素
public class OuterClass {
private String outerName;
private int outerAge;
public class InnerClass{
private int innerName;
InnerClass(){
//内部类可以访问外部类的元素
outerName="I am outer class";
outerAge=23;
}
public void display(){
System.out.println(outerName+" and my age is "+outerAge);
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.display();
}
}
在上面例子中我们可以看到,内部类可以直接访问外部类属性,尽管外部类属性是用private修饰的。这是因为在创建外部类时,内部类会自动捕获一个外部类的引用,所以内部类访问外部类元素,实际上是通过他所持有外部类引用访问的。在java中,我们可以通过OuterClass.this来获得外部类的引用,请看下面例子:
public class OuterClass {
public void display(){
System.out.println("this is OuterClass...");
}
public class InnerClass{
//获取外部类的引用
public OuterClass getOuterClass(){
return OuterClass.this;
}
public void innerDisplay(){
//内部类也可以通过外部类的引用访问外部元素
getOuterClass().display();
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.innerDisplay();
}
}
2.3 外部类可以通过内部类引用间接访问内部类元素
public class OuterClass {
public void display(){
//外部类访问内部类元素,需要通过内部类引用访问
InnerClass innerClass=new InnerClass();
innerClass.innerDisplay();
}
public class InnerClass{
public void innerDisplay(){
System.out.println("I am inner class");
}
}
public static void main(String[] args) {
OuterClass outerClass=new OuterClass();
outerClass.display();
}
}
三、创建内部类
3.1 在外部类外面(或外部类main方法)创建内部了对象
其实上面2.2例子中我们已经看到了如何创建内部类。如果要创建一个内部类对象,必须利用outerClass.new来创建:
1 OuterClass outerClass = new OuterClass();
2 OuterClass.InnerClass innerClass = outerClass.new InnerClass();
其实我们还可以一步到位: OuterClass.InnerClass innerClass=new OuterClass().new InnerClass();
内部类创建方法示例:
public static void main(String[] args) {
//先创建外部类对象,再创建内部类对象
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass1 = outerClass.new InnerClass();
innerClass1.innerDisplay();
//一步到位创建
OuterClass.InnerClass innerClass2=new OuterClass().new InnerClass();
innerClass2.innerDisplay();
}
3.2 在外部类里面创建内部类
正如2.3代码中display()方法那样,在外部类里面创建内部类,就像创建普通对象一样直接创建:
InnerClass innerClass=new InnerClass()
四、内部类的种类:
在Java中内部类主要分为成员内部类、方法内部类、匿名内部类、静态内部类。
4.1 成员内部类
成员内部类也是最普通的内部类,它是外部类的一个成员,所以他是可以无限制的访问外围类的所有成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
在成员内部类中要注意两点:
成员内部类中不能存在任何static的变量和方法
成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类
4.2 方法内部类
方法内部类定义在外部类的方法中,局部内部类和成员内部类基本一致,只是它们的作用域不同,方法内部类只能在该方法中被使用,出了该方法就会失效。 对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。
4.3 匿名内部类
匿名内部类其实就是一个没有名字的方法内部类,所以它符合方法内部类的所有约束,初次之外,还有一些地方需要注意:
匿名内部类是没有访问修饰符的。
匿名内部类必须继承一个抽象类或者实现一个接口
匿名内部类中不能存在任何静态成员或方法
匿名内部类是没有构造方法的,因为它没有类名。
一般使用匿名内部类的场景是,要继承或实现的接口只有一个抽象方法,比如添加一个 * :
public class Button {
public void click(){
//匿名内部类,实现的是ActionListener接口
new ActionListener(){
public void onAction(){
System.out.println("click action...");
}
}.onAction();
}
//匿名内部类必须继承或实现一个已有的接口
public interface ActionListener{
public void onAction();
}
public static void main(String[] args) {
Button button=new Button();
button.click();
}
}
4.4 静态内部类
关键字static可以修饰成员变量、方法、代码块,其实它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:
静态内部类的创建是不需要依赖于外围类,可以直接创建
静态内部类不可以使用任何外围类的非static成员变量和方法,而内部类则都可以
public class OuterClass {
private static String outerName;
public int age;
static class InnerClass1{
/* 在静态内部类中可以存在静态成员 */
public static String _innerName = "static variable";
public void display(){
/*
* 静态内部类只能访问外部类的静态成员变量和方法
* 不能访问外部类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + outerName);
}
}
class InnerClass2{
/* 非静态内部类中不能存在静态成员 */
public String _innerName = "no static variable";
/* 非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + outerName);
System.out.println("OuterClass age:" + age);
}
}
public void display(){
/* 外部类能直接访问静态内部类静态元素 */
System.out.println(InnerClass1._innerName);
/* 静态内部类可以直接创建实例不需要依赖于外部类 */
new InnerClass1().display();
/* 非静态内部的创建需要依赖于外部类 */
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
/* 非静态内部类的成员需要使用非静态内部类的实例访问 */
System.out.println(inner2._innerName);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
来源:https://www.cnblogs.com/xiayahui/p/6364118.html


猜你喜欢
- 传统界面的布局方式总是行列分明、坐落有序的,这种布局已是司空见惯,在不知不觉中大家都已经对它产生了审美疲劳。这个时候瀑布流布局的出现,就给人
- 前言随着标准Java的版本更新,开发者总是可以从升级后的版本中获取想要的功能。本文将给大家详细介绍下mac下面的java9版本安装使用,分享
- 如果一个对象不为空null时,把它赋给另外一个对象:像下面这个样子,需要把str的值赋给result,前提条件是在不为空null的前提之下:
- 前言static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优
- 本文介绍一个C#函数,可以实现计算文件的MD5值,可以用于文件传输后进行有效性校验。我们知道可以通过将一个字符串进行散列(Hash)运算得到
- 本文实例讲述了Android编程中自定义dialog用法。分享给大家供大家参考,具体如下:dialog是android中提供的一组弹出提示框
- 一、程序的三种结构顺序结构分支结构循环结构二、条件语句if 语句是最有用的控制结构之一。 if … else …语句的语法:if (布尔表达
- 本文实例讲述了Android使用ViewFlipper和GestrueDetector共同实现滑屏效果。分享给大家供大家参考,具体如下:关于
- jwt简介冒泡排序:(Bubble Sort)是一种简单的交换排序。之所以叫做冒泡排序,因为我们可以把每个元素当成一个小气泡,根据气泡大小,
- c#下压缩解压,主要是用第三方类库进行封装的。ICSharpCode.SharpZipLib.dll类库,链接地址为你官方下载链接。压缩主要
- JNI简介JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C
- 本文实例为大家分享了opencv检测直线之投影法的具体代码,供大家参考,具体内容如下以下是我对投影法的一点认识和实验:投影法就是数字图像在某
- 作为Android的四大组件之一,ContentProvider作为进程之间静态数据传递的重要手段,其在系统级别的应用中起了重大的作用。毫无
- 在任何的生产环境中我们都不可逃避并发这个问题,多线程作为并发问题的技术支持让我们不得不去了解。这一块知识就像一个大蛋糕一样等着我们去分享,抱
- 一、项目运行环境配置:Jdk1.8 + Tomcat8.5 + mysql + Eclispe(IntelliJ IDEA,Eclispe,
- BeanDefinitionRegistryPostProcessor概述可以看到BeanDefinitionRegistryPostPro
- Java的NIO中的管道,就类似于实际中的管道,有两端,一段作为输入,一段作为输出。也就是说,在创建了一个管道后,既可以对管道进行写,也可以
- Surface的拍照实现也是很简单,一个小demo就可以把流程看懂了。 话不多说,直接上代码布局文件<SurfaceView &nbs
- 优麒麟Ubuntu20.04中使用VS Code。VS Code的版本是1.48.0。以下内容仅限于上述环境,对于Windows环境下的使用
- Android开发之设置开机自动启动的几种方法方法一:<!-- 开机启动 --> <receiver android:na