一、为什么需要内部类?java内部类有什么好处?为什么需要内部类?
首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这
样做可以完成所有你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法的不就行了吗?
的确,以此作为设计内部类的理由,实在没有说服力。
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。二、内部类的基本定义在类的内部可以定义成员变量和方法,而且在类的内部也可以定义另一个类,如果类Outer的内部在定义一个类Inner,此时Inner就成为内部类,而Outer则称为外部类。
内部类可以声明为public或private。当内部类声明为public或private,对其访问权限于成员变量和成员方法完全相同。代码如下:package com.se.innerclass;
class Outer {
private String info = "我爱你中国";
class Inner{
public void print() {
System.out.println(info);
}
}
public void fun() {
new Inner().print();
}
}
public class InnerClassDemo1 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun();
}
}
输出结果:
以上的程序中可以清楚的发现,Inner类作为Outer类的内部类存在,并且外部类的fun()方法中直接实例化内部类的对象调用方法print(),但是从代码中可以明显发现,内部类的存在实际上破坏了一个类的基本结构,因为类是由属性及方法组成的,所以这是内部类的一个缺点,那么内部类有哪些优点呢,如果把内部类拿到外面来就能发现内部类的优点了。
如下面的代码:package com.se.innerclass;class Outer {
private String info = "我爱你中国";
public void fun() {
new Inner(this).print();
}
public String getInfo(){
return info;
}
}
class Inner{
private Outer outer;
public Inner(Outer outer){
this.outer = outer;
}
public void print() {
System.out.println(outer.getInfo());
}
}
public class InnerClassDemo2 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun();
}
}
以上程序完成了内部类同样的功能,但是但是代码明显比之前的更加复杂,所以内部类的唯一好处就是可以方便的访问外部类的私有属性。三、使用static定义外部类使用static可以声明属性或方法,而使用static也可以声明内部类,用static声明内部类变成了外部类,但是用static声明的内部类不能访问非static的外部类属性。package com.se.innerclass;class Outer{
private static String info = "我爱你中国";
static class Inner{
public void print() {
System.out.println(info);
}
}
}
public class InnerClassDemo3{
public static void main(String[] args) {
new Outer.Inner().print();
}
}
以上程序将info属性定义成了static类型,这样程序中就可以通过static声明的内部类直接访问此static属性,当然,如果此时info属性不是static类型,则编译时将出现以下错误:
’
四、在外部类访问内部类一个内部类除了可以通过外部类访问,也可以直接在其他类当中调用,调用的基本格式为:
外部类.内部类 内部类对象 = 外部类实例.new 内部类()
以上的操作格式中,首先要找到外部类的实例化对象之后才可以通过外部类的实例化对象去实例化内部类对象。
这里我们可以观察到编译之后的内部类的.class文件。
内部类定义之后,生成的.class文件是以Outer$Inner的形式存在的,在Java中只要文件存在$,则在程序中应将其替换为”.”。
在外部访问内部类代码如下:package com.se.innerclass;class Outer{
private String info = "我爱你中国";
class Inner{
public void print() {
System.out.println(info);
}
}
}public class InnerClassDemo4 {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.print();
}
}
五、在方法中定义内部类也可以在方法类定义一个内部类,但是在方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数要想被内部类所访问,则参数前必须加上final关键字。
在方法中定义内部类:package com.se.innerclass;class Outer{
private String info = "我爱你中国";
public void fun(final String temp){
class Inner{
public void print(){
System.out.println(info);
System.out.println(temp);
}
}
new Inner().print();
}
}public class InnerClassDemo5 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun("123");
}
}
六、匿名内部类
在java中处理内部类之外,还有一种匿名内部类。匿名内部类就是指没有一个具体名称的类,此概念是在接口和抽象类的应用上发展起来的,那么匿名内部类有哪些作用呢?
一个简单的操作:package com.se.innerclass;
/**
* 普通实现
* @author wzy
*
*/
interface A {
public void printInfo();
}
class B implements A{
@Override
public void printInfo() {
System.out.println("Hello world!!!");
}
}
class X{
public void fun1(){
this.fun2(new B());
}
public void fun2(A a){
a.printInfo();
}
}
public class NoInnerClassDemo6 {
public static void main(String[] args) {
new X().fun1();
}
}
通过以上的方法可以实现相应的功能,但是现在如果接口实现类只使用一次,那么还有必要单独定义一个子类B吗?很显然是没有必要的,所以此时就可以使用匿名内部类完成,代码修改如下:package com.se.innerclass;
interface A{
public void printInfo();
}
class X{
public void fun1() {
this.fun2(new A(){
@Override
public void printInfo() {
System.out.println("hello world");
}});
}
public void fun2(A a) {
a.printInfo();
}
}
public class NoInnerClassDemo7 {
public static void main(String[] args) {
new X().fun1();
}
}
七、内部类的扩展在接口内部可以添加抽象类,在抽象类内部可以添加接口,由于使用较少,不做过多介绍。
内部类:
(一):定义:
把类定义在另一个类的内部,该类就被称为内部类。
举例:下面用代码进行体现 class Outer {
class Inner {
}
}
(二) 内部类的访问规则
A:可以直接访问外部类的成员,包括私有 B:外部类要想访问内部类成员,必须创建对象(三) 内部类的分类
A:成员内部类 B:局部内部类 C:静态内部类 D:匿名内部类
(1) 成员内部类
成员内部类——就是位于外部类成员位置的类
特点:可以使用外部类中所有的成员变量和成员方法(包括private的)
A 格式:class Outer {
private int age = 20;
//成员位置
class Inner {
public void show() {
System.out.println(age);
}
}
}
class Test {
public static void main(String[] ages) {
//成员内部类是非静态的演示
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
B:创建对象时: //成员内部类不是静态的:
外部类名.内部类名 对象名 = new 外部类名.new 内部类名();
//成员内部类是静态的:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
C:成员内部类常见修饰符:
*****A:
private如果我们的内部类不想轻易被任何人访问,可以选择使用private修饰内部类,这样我们就无法通过创建对象的方法来访问,想要访问只需要在外部类中定义一个public修饰的方法,间接调用。这样做的好处就是,我们可以在这个public方法中增加一些判断语句,起到数据安全的作用。class Outer {
private class Inner {
public void show() {
System.out.println(“密码备份文件”);
}
}
public void method() {
if(你是管理员){
Inner i = new Inner();
i.show();
}else {
System.out.println(“你没有权限访问”);
}
}
}
下面我们给出一个更加规范的写法:class Outer {
private class Inner {
public void show() {
System.out.println(“密码备份文件”);
}
}
//使用getXxx()获取成员内部类,可以增加校验语句(文中省略)
public Inner getInner() {
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.getInner();
inner.show();
}
}
****B:static
这种被 static 所修饰的内部类,按位置分,属于成员内部类,但也可以称作静态内部类,也常叫做嵌套内部类。具体内容我们在下面详细讲解。****D:成员内部类经典题(填空)
请在三个println 后括号中填空使得输出25,20,18class Outer {
public int age = 18;
class Inner {
public int age = 20;
public viod showAge() {
int age = 25;
System.out.println(age);//空1
System.out.println(this.age);//空2
System.out.println(Outer.this.age);//空3
}
}
}
(2) 局部内部类
局部内部类——就是定义在一个方法或者一个作用域里面的类
特点:主要是作用域发生了变化,只能在自身所在方法和属性中被使用
A: 格式class Outer {
public void method(){
class Inner {
}
}
}
B:访问时://在局部位置,可以创建内部类对象,通过对象调用和内部类方法
class Outer {
private int age = 20;
public void method() {
final int age2 = 30;
class Inner {
public void show() {
System.out.println(age);
//从内部类中访问方法内变量age2,需要将变量声明为最终类型。
System.out.println(age2);
}
}
Inner i = new Inner();
i.show();
}
}
C: 为什么局部内部类访问局部变量必须加final修饰呢?
******因为局部变量是随着方法的调用而调用,使用完毕就消失,而堆内存的数据并不会立即消失。所以,堆内存还是用该变量,而该变量已经没有了。为了让该值还存在,就加final修饰。原因是,当我们使用final修饰变量后,堆内存直接存储的是值,而不是变量名。(即上例 age2 的位置存储着常量30 而不是 age2 这个变量名)
(3) 静态内部类我们所知道static是不能用来修饰MT4下载教程类的,但是成员内部类可以看做外部类中的一个成员,所以可以用static修饰,这种用static修饰的内部类我们称作静态内部类,也称作嵌套内部类.
特点:不能使用外部类的非static成员变量和成员方法
解释:非静态内部类编译后会默认的保存一个指向外部类的引用,而静态类却没有。简单理解:即使没有外部类对象,也可以创建静态内部类对象,而外部类的非static成员必须依赖于对象的调用,静态成员则可以直接使用类调用,不必依赖于外部类的对象,所以静态内部类只能访问静态的外部属性和方法。class Outter {
int age = 10;
static age2 = 20;
public Outter() {
}
static class Inner {
public method() {
System.out.println(age);//错误
System.out.println(age2);//正确
}
}
}
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
inner.method();
}
}
(4) 匿名内部类一个没有名字的类,是内部类的简化写法
A 格式: new 类名或者接口名() {
重写方法();
}
本质:其实是继承该类或者实现接口的子类匿名对象这也就是下例中,可以直接使用 new Inner() {}.show(); 的原因 == 子类对象.show();interface Inner {
public abstract void show();
}
class Outer {
public void method(){
new Inner() {
public void show() {
System.out.println("HelloWorld");
}
}.show();
}
}
class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
如果匿名内部类中有多个方法又该如何调用呢?Inter i = new Inner() { //多态,因为new Inner(){}代表的是接口的子类对象
public void show() {
System.out.println("HelloWorld");
}
};
B:匿名内部类在开发中的使用我们在开发的时候,会看到抽象类,或者接口作为参数。而这个时候,实际需要的是一个子类对象。如果该方法仅仅调用一次,我们就可以使用匿名内部类的格式简化。
————————————————
原文链接:https://blog.csdn.net/weixin_42899466/article/details/82705062