Java 中的内部类
前言
在第一次把Java 编程思想中的内部类这一章撸完后,有点印象。大概知道了什么时内部类,局部内部类,匿名内部类,嵌套内部类。随着时间的推移,自己慢慢的就忘记了,总感觉自己思考的东西不多,于是
看了第二遍,并把自己的想法和一些笔记写下来。供以后参考。
内部类
定义:如果把A类定义再B类里面,那么把A类叫做 内部类
代码如下:
public class B {
public class A{}
}
这样看内部类是不是感觉很简单?定义确实很简单,但是思考一下,这样定义一个内部类有什么意义吗?或者说能带来什么好处? 上面那样定义,个人感觉是意义不大。所以 ,我们一般定义内部类,都是需要内部类实现一个接口或着抽象类。有实际意义的代码如下(例子来自,java编程思想):
/**
* @ClassName Selector
* @Description 选择器
* @Author ouyangkang
* @Date 2019-03-12 14:21
**/
public interface Selector {
// 是否结束
boolean end();
// 当前数据
Object current();
// 下一个节点
void next();
}
/**
* @ClassName Squence
* @Description TODO
* @Author ouyangkang
* @Date 2019-03-12 14:24
**/
public class Squence {
private Object[] items;
private int next;
public Squence(int size) {
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
private class SequceneSelector implements Selector {
private int i;
@Override
public boolean end() {
return i == items.length;
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if (i < items.length) {
i++;
}
}
}
public Selector selector(){
return new SequceneSelector();
}
}
class Test{
public static void main(String[] args) {
Squence squence = new Squence(10);
for (int i = 0; i < 10 ; i++) {
squence.add(i);
}
// 调用内部类 这是迭代器模式的一个例子。 通过内部类 ,访问类中的私有属性。
Selector selector = squence.selector();
while (!selector.end()){
System.out.print(selector.current()+" ");
selector.next();
}
}
}
输出: 0 1 2 3 4 5 6 7 8 9
请仔细查看上面代码。 这是个非常好的例子。访问权限为 private 的内部类 SequceneSelector 实现了 Selector 接口 ,该内部类可以访问外部类 Squence 中私有属性 items 。 并提供一个公开的方法 selector ,返回一个,向上转型为 Selector 类型。 在测试代码中。先创建 squence 对象。 往里面添加10个元素。 并调用该对象的中的 selector() 方法,返回一个 Selector 类型的对象。 根据我们定义的 Selector 接口中方法的含义,编码。打印输出。
上面代码说明了内部类的几个好处:
- 隐藏了细节,实现一个接口,向上转型。
- 可以访问外部类中的所有私有属性,方法。就像是拥有他们一样。但是不是拥有(你可以把它想成一个成员方法)
我觉得第一点没什么好说的,反倒是第二点,自己是这样理解的:外部类就像是一个房子,里面的成员变量,方法,内部类。就像是房子里面的人。可以相互通信。而内部类实现了一个接口或着抽象类后,就有点像细作一样,表面看起来是房子里面的人,其实真正是外面的人。只要我创建它,并通过向上转型,就可以到外面去通信。
局部内部类
定义: 如果把A类定义再B类的方法中,那么把A类叫做局部内部类
代码如下:
public class A {
private void getB(){
class B{}
}
}
其实上面代码意义并不大。 下面看下一些有意义的代码。代码如下:
/**
* @InterfaceName Destination
* @Description TODO
* @Author ouyangkang
* @Date 2019-03-12 19:59
**/
public interface Destination {
String readLabel();
}
/**
* @ClassName Parcel
* @Description TODO
* @Author ouyangkang
* @Date 2019-03-12 20:00
**/
public class Parcel {
public Destination destination(String str){
class PDestination implements Destination{
private String label = str;
public PDestination(String label){
this.label = label;
}
@Override
public String readLabel() {
return label;
}
}
return new PDestination(str);
}
public static void main(String[] args) {
Parcel parcel = new Parcel();
Destination destination = parcel.destination("hello");
System.out.println(destination.readLabel());
}
}
输出 hello
定义一个为 Destination 的接口,方法为 readLabel() 。 Parcel 类中定义了一个 返回 Destination 类型的方法。 该方法中定义了一个 PDestination 类,并实现了 Destination 接口。 在最后返回PDestination 的对象。 上面局部内部类很熟悉把。下面,我们看下匿名内部类。
匿名内部类
将上面Parcel类修改 ,代码如下
/**
* @ClassName Parcel1
* @Description TODO
* @Author ouyangkang
* @Date 2019-03-13 15:33
**/
public class Parcel1 {
public Destination destination(final String str){
return new Destination() {
private String label = str;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel1 parcel1 = new Parcel1();
Destination ouyangkang = parcel1.destination("hello");
System.out.println(ouyangkang.readLabel());
}
}
输出:hello
类 Parce1 中的 destination() 方法直接 new 了一个 Destination 对象,重写该 readLabel() 方法。 这样返回没有名字的局部内部类类,称为匿名内部类。
局部内部类 VS 匿名内部类
在使用局部内部类或着匿名内部类的时候,要使用外部类中的局部变量是,该变量要为final ,要问为为什么,因为局部内部类或着匿名内部类内部对局部变量操作并不会改变改内容,所以为了防止使用错误。就用final修饰。不可变。其根本原因就是不会有任何的变化。
那么什么时候用局部内部类,什么时候用匿名内部类?
在你需要一个已命名的构造器,或着需要重构构造器。需要的不止是该一个内部类对象。就是你要定义多个构造器的时候用局部内部类。如果不需要就用匿名内部类。
JAVA 8 可以用Lambda 表达式表示
上面 Parcel1 类 用 JAVA 8 编码如下
public class Parcel2 {
public Destination destination(final String str) {
return ()->{
String label = str;
return label;
};
}
public static void main(String[] args) {
Parcel2 parcel2 = new Parcel2();
Destination ouyangkang = parcel2.destination("hello");
System.out.println(ouyangkang.readLabel());
}
}
输出:hello
嵌套类
如果把A类定义在B类中,并A类用static关键字修饰,那么把A叫做嵌套类。
代码如下:
publc class B{
static class A{}
}
如果不需要内部类和外部类有关系,就把该内部类声明为 static 。
创建嵌套类代表:
- 并不需要外围类对象
- 不能从嵌套类的对象中访问外部类中的 非静态的东西。
我一般用嵌套类来做测试类。嵌套类理解就到此为止了
总结
总的来说,Java 中的 内部类并没有想象的的那么难理解和认知,但是内部类使用起来就比较深奥了,其中多态这一特性在,配合着内部类,可谓说贼强了。隐藏细节,关注接口中方法本身的意思。
Java 中的内部类的更多相关文章
- Java中的内部类(成员内部类、静态内部类、局部内部类、匿名内部类)
Java中的内部类(成员内部类.静态内部类.局部内部类.匿名内部类) 神话丿小王子的博客主页 我们先看这样一段话:人是由大脑.肢体.器官等身体结果组成.而组成我们人体的心脏它也有自己的属性和行为(血液 ...
- Java中的 内部类(吐血总结)
1. 内部类的作用 内部类是一个独立的实体,可以用来实现闭包:能与外部类通信:内部类与接口使得多继承更完整 2. 内部类的分类 1)普通内部类 类的实例相关,可以看成是一个实例变量.内部类的类名由 “ ...
- 【转】Java中的内部类和匿名类
Java内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的 ...
- Java学习笔记二十:Java中的内部类
Java中的内部类 一:什么是内部类: (1).什么是内部类呢? 内部类( Inner Class )就是定义在另外一个类里面的类.与之对应,包含内部类的类被称为外部类. (2).那为什么要将一个类定 ...
- Java中的内部类怎么用
一.为什么需要内部类?java内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时 ...
- Java中的内部类(回调)
一.内部类的主要作用如下: 1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类 2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据 3. 内部类所 ...
- 【Java基础】4、java中的内部类
内部类的分类:常规内部类.静态内部类.私有内部类.局部内部类.匿名内部类. 实例1:常规内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 ...
- Java中的内部类————以及jdk1.8的lambda表达式
一.内部类学习导图 1>.静态内部类: 使用static修饰符来修饰内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象.因此使用static修饰的内部类被称为静态内部类. publi ...
- Java基础(十五):Java 中的内部类
问:什么是内部类呢? 答:内部类( Inner Class )就是定义在另外一个类里面的类.与之对应,包含内部类的类被称为外部类. 问:那为什么要将一个类定义在另一个类里面呢?清清爽爽的独立的一个类多 ...
随机推荐
- Luogu P3600 随机数生成器(期望+dp)
题意 有一个长度为 \(n\) 的整数列 \(a_1, a_2, \cdots, a_n\) ,每个元素在 \([1, x]\) 中的整数中均匀随机生成. 有 \(q\) 个询问,第 \(i\) 个询 ...
- linux下sort命令详解大全
工作原理: Sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. 第一部分: 1. sort:(不带参数) [rocrocket@ ...
- bzoj4514 数字配对
思路 首先想到费用流. 对于每个点拆点.然后考虑我们怎样才能保证每个点只被用一次. 如果\(i\)与\(j\)满足条件.那么就从\(i\)向\(j\)连一条边并且从\(j\)向\(i\)连一条边.这样 ...
- 第八节:Task的各类Task<TResult>返回值以及通用线程的异常处理方案。
一. Task的各种返回值-Task<TResult> PS: 在前面章节,我们介绍了Task类开启线程.线程等待.线程延续的方式,但我们并没有关注这些方式的返回值,其实他们都是有返回值的 ...
- javaScript事件机制深入学习(事件冒泡,事件捕获,事件绑定方式,移除事件方式,阻止浏览器默认行为,事件委托,模拟浏览器事件,自定义事件)
前言 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软 ...
- react+antdesign
http://scaffold.ant.design/#/scaffolds/ng-alain http://scaffold.ant.design/#/scaffolds/react-redux-a ...
- unicode & utf-8
简单来说: Unicode 是「字符集」 UTF-8 是「编码规则」 其中: 字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point) 编码规则:将「码位」转换为 ...
- 新手如何理解JS面向对象开发?
今天有时间讲讲我对面向对象的理解跟看法,尽量用通俗的语言来表达,多多指教! 如今前端开发已经越来越火了,对于前端开发的要求也是越来越高了,在面试中,经常有面试官会问:你对JS面向对象熟悉吗? 其实,也 ...
- 【easy】263. Ugly Number 判断丑数
class Solution { public: bool isUgly(int num) { ) return false; ) return true; && num % == ) ...
- typecho视频播放插件JWPlayer
JWplayer for typecho是羽中大神开发并持续维护的一款插件,目前插件已经发布了8个版本,涵盖typecho0.8到1.0,插件基于原生的JWPlayer,可以说非常完美,详细使用方法在 ...