一、什么是内部类?

内部类(inner class)是定义在另一个类中的类

为什么使用内部类?

1)内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据

2)内部类可以对同一个包中的其他类隐藏起来

3)当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷

二、内部类有几种?

内部类分为:成员内部类、局部内部类、静态内部类、匿名内部类

2.1、成员内部类

成员内部类是最普通的内部类,我们先从它开始说起:

package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-08 16:53
* modify:{modify}
*/
public class Outer { private String id;
private String name; public class Inner { public void print() {
id = "";
name = "李明";
System.out.println(id);
System.out.println(name);
}
} public void start() {
Inner inner = new Inner();
inner.print();
}
}

执行结果:

1001
李明

Inner是一个内部类,内部类可以访问外部类定义的所有属性和方法,包括私有属性

内部类的对象总有一个隐式的引用,它指向创建它的外部类对象,也是通过这个隐式引用,内部类可以访问外部类的属性和方法,图示如下:

所以System.out.println(name)等价于System.out.println(Outer.this.name),格式为:外部类.this.属性/方法名,下面一个例子,可以加深我们的理解

package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-08 16:53
* modify:{modify}
*/
public class Outer { private String id = "1";
private String name = "张三"; public class Inner { private String name = "李四"; public void print() {
String name = "王五";
System.out.println(id);
System.out.println(name);
System.out.println(this.name);
System.out.println(Outer.this.name);
}
} public void start() {
Inner inner = new Inner();
inner.print();
}
}

执行结果:

1
王五
李四
张三

内部类可以拥有private、protected、public、包访问权限(默认),而外部类只有public和包访问权限(protected)

注意:成员内部类不能含有static修饰的变量和方法,因为成员内部类需要先创建外部类,才能创建自己

2.2、局部内部类

局部内部类是定义在一个方法或者作用域中的类

package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-08 16:53
* modify:{modify}
*/
public class Outer { public void print(final String name) {
class Inner {
public void innerPrint() {
System.out.println(name);
}
}
Inner inner = new Inner();
inner.innerPrint();
}
}

如果需要从外部类的print方法传参到内部类中,形参必须为final类型。因为在方法print执行结束以后,变量会被释放,然而内部类的对象可能仍然在使用这个变量,只有声明为final常量,才不会导致程序报错。所以传入的参数,不可以修改值

局部内部类不可以使用public或private访问修饰符

2.3、静态内部类

静态内部类,修饰符为static的内部类

package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-08 16:53
* modify:{modify}
*/
public class Outer { private static String name = "李明"; public static class Inner { public void print() {
System.out.println(name);
}
}
}

可以直接使用Outer.Inner的方式进行调用,静态类中只可以访问外部类的静态属性和方法

2.4、匿名内部类

以上三种内部类,我们在平常编程中使用较少。但是匿名内部类我们会经常遇到,在各种框架中也经常出现它的身影。同时后面的篇章中会说到的lambda表达式,很大的一个作用就是为了简便匿名内部类的写法。所以我们要着重讲一下匿名内部类,上面三种内部类,有所了解即可

在2.2中我们说到了局部内部类,如果我们再深入一步。假如,在方法中内部类,我们只创建这个类的一个对象,我们就可以不用声明了,这种类被称为匿名内部类。前提是这个内部类要有父类或者实现某个接口

package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-09 15:03
* modify:{modify}
*/
public interface Printable { void print();
}
package com.my.po;

/**
* description:{description}
* author:jyy
* date:2018-02-08 16:53
* modify:{modify}
*/
public class Outer { public void start() {
class Inner implements Printable {
@Override
public void print() {
System.out.println("实现接口的局部内部类");
}
}
Inner inner = new Inner();
inner.print(); System.out.println("======================"); Printable printable = new Printable() {
@Override
public void print() {
System.out.println("匿名内部类,重写了接口的方法");
}
};
printable.print();
}
}
package com.my.controller;

import com.my.po.Outer;
import junit.framework.TestCase;
import org.junit.Test; /**
* description:{description}
* author:jyy
* date:2018-01-09 16:43
* modify:{modify}
*/
public class AppTest extends TestCase { @Test
public void test() { Outer outer = new Outer();
outer.start();
}
}

执行结果:

实现接口的局部内部类
======================
匿名内部类,重写了接口的方法
package com.my.controller;

import com.my.po.Outer;
import junit.framework.TestCase;
import org.junit.Test; /**
* description:{description}
* author:jyy
* date:2018-01-09 16:43
* modify:{modify}
*/
public class AppTest extends TestCase { @Test
public void test() { Object obj1 = new Object();
System.out.println(obj1.toString()); Object obj2 = new Object() {
public String toString() {
return "ok";
}
};
System.out.println(obj2.toString());
}
}

执行结果:

java.lang.Object@306a30c7
ok

匿名内部类同样不可以使用public或private访问修饰符,同样也不可以被static修饰

匿名内部类是唯一一个没有构造器的类,因为构造器的名字必须和类名相同,而匿名内部类连类名都没有

同样父类方法start的传参也是默认final修饰的,也就是说匿名内部类不能修改传入参数的值

三、匿名内部类的使用

匿名内部类的主要使用场景:1、事件监听2、回调

请看下面的示例

        try {
/**
* 代码
*/
} catch (Exception e) {
logger.error("This is error message.Exception:" + e);
e.printStackTrace();
} finally {
System.out.println("退出");
}

上面这种格式,相信大家都很熟悉,当我们需要监控代码异常的时候,会在程序大量使用这种代码。然而这段代码中只有try中的部分是需要经常变动的,其他的部分基本不变,我们试着用匿名内部类的方式,重写这部分代码

首先定义一个接口

package com.my.controller;

/**
* description:{description}
* author:jyy
* date:2018-02-09 15:42
* modify:{modify}
*/
public interface CatchExceptionable {
void catchException();
}

再定义一个异常处理的模板类

package com.my.controller;

import org.apache.log4j.Logger;

/**
* description:{description}
* author:jyy
* date:2018-02-09 15:40
* modify:{modify}
*/
public class ExceptionTemplate { private static Logger logger = Logger.getLogger(ExceptionTemplate.class); public void execute(CatchExceptionable catchExceptionable) {
try {
catchExceptionable.catchException();
} catch (Exception e) {
logger.error("This is error message.Exception:" + e);
e.printStackTrace();
} finally {
System.out.println("退出");
}
}
}

当我们写代码的时候,可以像如下方式进行调用,这样我们就不必重复的写try catch这类代码了,提高了复用性

        new ExceptionTemplate().execute(new CatchExceptionable() {
@Override
public void catchException() {
/**
* 代码
*/
}
});

JAVA基础知识|内部类的更多相关文章

  1. JAVA基础知识|lambda与stream

    lambda与stream是java8中比较重要两个新特性,lambda表达式采用一种简洁的语法定义代码块,允许我们将行为传递到函数中.之前我们想将行为传递到函数中,仅有的选择是使用匿名内部类,现在我 ...

  2. 学习android学习必备的java基础知识--四大内部类

    学习android必备的java基础知识--四大内部类 今天学习android课程,因为我的主专业是JAVA,但是兴趣班却有这其他专业的同学,学习android 需要具备一些java的基础知识,因此就 ...

  3. java基础知识小总结【转】

    java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...

  4. Java 基础知识总结

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.数据类型:  数据类型:1>.基本数据类型:1).数值型: 1}.整型类型(byte  8位   (by ...

  5. Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  6. 毕向东—Java基础知识总结(超级经典)

    Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...

  7. java基础知识-笔记整理

    1.查看已安装jdk文件路径 CMD输入java -verbose.   2.java学习提升路线 java学习视屏地址: http://www.icoolxue.com/album/show/38 ...

  8. Java 基础知识总结1

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.数据类型:  数据类型:1>.基本数据类型:1).数值型: 1}.整型类型(byte  8位   (by ...

  9. java基础知识文章汇总

    将之前的所有关于Java基础知识的随笔,整理成质量较高的十几篇随笔,几乎是好几篇比较零散的随笔合成现在的一篇,自认为还不错. java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规 ...

随机推荐

  1. 为什么领域模型对于架构师如此重要? https://blog.csdn.net/qq_40741855/article/details/84835212

    为什么领域模型对于架构师如此重要? https://blog.csdn.net/qq_40741855/article/details/84835212 2018年12月05日 14:30:19 绝圣 ...

  2. centos7安装google浏览器

    1. 配置yum源 在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repo cd /ect/yum.repos.d/ vim google-chrome.repo ...

  3. K2 BPM_快消零售连锁行业门店选址解决方案_十年专注业务流程管理系统

    >>>业务流程管理软件选型攻略  快消零售连锁行业门店选址解决方案   业内有句名言:“门店最重要的是什么?第一是选址,第二是选址,第三还是选址” 选址是一个很复杂的综合性商业决策过 ...

  4. Image Processing and Analysis_8_Edge Detection:Learning to Detect Natural Image Boundaries Using Local Brightness, Color, and Texture Cues ——2004

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  5. JSONPlaceholder - 免费的在线REST服务(提供测试用的HTTP请求假数据)

    http://www.hangge.com/blog/cache/detail_2020.html 一.GET 方式请求数据1,获取文章(贴子)数据 二.POST 方式请求数据1,功能说明我们可以将数 ...

  6. linux 、 CentOs ---> 环境变量设置

    Linux下环境变量设置 1.在Windows 系统下,很多软件安装都需要配置环境变量,比如 安装 jdk ,如果不配置环境变量,在非软件安装的目录下运行javac 命令,将会报告找不到文件,类似的错 ...

  7. ubuntu---记录. opencv3.4.7

    一.下载 https://github.com/opencv/opencv/archive/3.4.7.zip wget -c https://github.com/opencv/opencv/arc ...

  8. 三道习题(1、将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别。 #输入格式:按字典序由小到大输入若干个单词,每个单词占一行,以end结束输入。)

    #coding=gbk ''' 1.将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别. #输入格式:按字典序由小到大输入若干 ...

  9. Linux系统运维之修炼秘法

    在这个现如今的互联网高速发展的时代,如何才能保持住一门铁的饭碗.无疑最稳妥的自然就是选择一门任何时代都不会落伍的技能,来选择深入学习研究.大家可能觉得这一期的Linux就该这么学的话题比较世俗.但是不 ...

  10. DNS域名解析系统介绍

    域名系统(D N S)是一种用于T C P / I P应用程序的分布式数据库,它提供主机名字和 I P地址之间的转换及有关电子邮件的选路信息.这里提到的分布式是指在 I n t e r n e t上的 ...