1. 内部类的作用

内部类是一个独立的实体,可以用来实现闭包;能与外部类通信;内部类与接口使得多继承更完整

2. 内部类的分类

1)普通内部类

类的实例相关,可以看成是一个实例变量。内部类的类名由 “外部类.内部类” 确定。

普通内部类不能声明 static相关的变量或方法。内部类可以直接访问外部类的所有成员(包括 private成员),隐式或显式(外部类.this)。而外部类可以 new 内部类,实例相关的可以直接 new,static 相关(类相关)需要使用实例的引用去 引用.new。内部类 class 前可以添加 private 与 protected 表示只对其外部类或其子类有访问权限。

final class Demo {
private int m = 4; private Demo() {
System.out.println("Demo initial");
} private class Inner {
private int i = 23; Inner() {
System.out.println("Inner initial");
}
private void f() {
System.out.println("f method" + " i:" + this.i + " m:" + Demo.this.m);
}
} public static void main(String[] args) {
Demo demo = new Demo();
System.out.println("Dispatch Inner class");
Demo.Inner inn = demo.new Inner();
inn.f();
} }
/* out:
Demo initial
Dispatch Inner class
Inner initial
f method i:23 m:4 *///~

* 关于闭包

Java 中通过 内部类指向顶级类的指针(Demo.this) 访问顶级类中的(又称内部类所在词法作用域)变量。其中 Demo.this ,表示的是顶级类的上下文;而内部类中的 this (可省略)表示的是内部类上下文。

Js 中只有一个 this,它既可以访问函数体外部又可以访问函数体内部。先在内部寻找,如果找不到则去外部寻找。而去外部找就是所谓的闭包引用。闭包又称为词法闭包。

var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func:" + this);
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
console.log("inner func:" + this)
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}());
}
}; myObject.func(); //output:
outer func:[object Object]
outer func: this.foo = bar
outer func: self.foo = bar
inner func:[object Window]
inner func: this.foo = undefined
inner func: self.foo = bar

* 注意:

在原型继承的情况下,如果函数无法找到其所有者/调用者(sush as  IIFE),那么在非严格模式下函数内的 this 指向 window 对象。关于变量,一般情况下 this 先访问该函数内部的变量,再去函数所在词法作用域寻找,如果还找不到则去 window 作用域寻找。而去 window 里找变量通常是危险的,这时就需要使用参数或其它方式保存变量。从 关于 lambda 表达式中的 this 一文中,可以得出:lambda 去上一个调用者/window 对象。 从 深入浅出 JavaScript 中的 this,而对于使用 new Foo() 构造函数调用,this 指向到新的对象,普通变量不受影响。
for (var i = 0; i < 5; i++) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.addEventListener('click', function(){ console.log(i); });
document.body.appendChild(btn);
} //提供两种基本解决思路: for (var i = 0; i < 5; i++) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
btn.a = i
btn.addEventListener('click', function(){ console.log(this.a); });
document.body.appendChild(btn);
} for (var i = 0; i < 5; i++) {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('Button ' + i));
//使用 IIFE 的方式有个副作用,函数体内代码立即执行。而这里不应立即执行,故返回一个函数,延迟执行。
btn.addEventListener('click', (function(arg){ return function() {console.log(arg);} })(i));
document.body.appendChild(btn);
}

2)局部内部类

方法和作用域中的内部类称为局部内部类,只在其词法作用域中可被访问。可以重载构造器。

3)匿名内部类

匿名内部类引用外部类方法中的局部变量必须是 final的原因:对于外部类方法中的局部变量,在该方法调用完成后从栈中清除( remove from stack) ,这时匿名内部类对象将变得无法访问它们。如果将这些变量声明为 final,他们实际上将不再是一个变量而变成了常量,编译器将在编译时把它们替换为具体的常量。(也有观点认为局部变量整体复制,final 保证一致性。)

匿名内部类没有具名构造器,new Wrapper(x) {} 将值传递给基类的构造器。可以被匿名内部类直接引用,不需要 final。

abstract class Base {
public Base(int i) {
System.out.println("Base constructor, i=" + i + "\n");
} public abstract void f();
} class AnonymousConstructor {
private int m = 10000;
public Base getBase(int i, final int outer) {
return new Base(i) { //这里引用 局部变量 i,是被匿名内部类的基类使用,不需要声明 final。
{
System.out.println("AnonymousInnerClass instance initializer\n");
}
@Override
public void f() {
// 局部变量 outer 也是被匿名内部类直接使用,需要声明为 fianl
System.out.println("This variable must declare final first: " + outer + "\n"); // 不同于前面对局部变量 i 的使用,这里是匿名直接使用,则需要声明 final。否则报错!(java 8 或以上除外)
//System.out.println("This variable must declare final first: " + i + "\n"); // 对非局部变量 m 的使用,不需要声明 final。m 等同与 AnonymousConstructor.this.m
System.out.println(m); }
};
} public static void main(String[] args) {
AnonymousConstructor ac = new AnonymousConstructor();
Base base = ac.getBase(3, 9);
base.f();
}
}

4)嵌套类

如果不需要内部类对象与其外部类对象之间有联系,那么可以将内部类声明为 static,称之为静态内部类或嵌套类。特点是:创建嵌套类的实例不需要其外围类的实例;不能从嵌套类的实例中访问非静态的外围类的实例(没有 this 引用);嵌套类不会随外部类加载而初始化。接口内部的类自动是 public static 的,可以将嵌套类放入接口中,从而使得他们可以被该接口的不同实现所共用。

final class Demo {
private int m = 4;
private static int n = 6; private Demo() {
System.out.println("Demo initial");
} static class Inner {
private int i = 23; Inner() {
System.out.println("Inner initial");
}
private void f() {
System.out.println("f method" + " i:" + this.i + " n:" + Demo.n);
}
} public static void main(String[] args) {
// Demo.Inner inn = new Inner(); // Inner initial
// inn.f(); // f method i:23 n:6
new Demo(); // Demo initial
} }
/* out:
Demo initial *///~

*  关于 java 中的 interface:

正如 接口内部的类自动是 public static 的,类中 嵌套的接口 (nested interface)也是自动 "static" 的,并且能够被移除。同样的,interface  方法上的 "public" 和域名上的 "public final" 也可以被移除。嵌套 interface 示例:

public class Foo {
public interface Bar {
void callback();
}
public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
public void callback() {...}
});

Java中的 内部类(吐血总结)的更多相关文章

  1. Java中的内部类(成员内部类、静态内部类、局部内部类、匿名内部类)

    Java中的内部类(成员内部类.静态内部类.局部内部类.匿名内部类) 神话丿小王子的博客主页 我们先看这样一段话:人是由大脑.肢体.器官等身体结果组成.而组成我们人体的心脏它也有自己的属性和行为(血液 ...

  2. Java 中的内部类

    前言 在第一次把Java 编程思想中的内部类这一章撸完后,有点印象.大概知道了什么时内部类,局部内部类,匿名内部类,嵌套内部类.随着时间的推移,自己慢慢的就忘记了,总感觉自己思考的东西不多,于是 看了 ...

  3. 【转】Java中的内部类和匿名类

       Java内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的 ...

  4. Java学习笔记二十:Java中的内部类

    Java中的内部类 一:什么是内部类: (1).什么是内部类呢? 内部类( Inner Class )就是定义在另外一个类里面的类.与之对应,包含内部类的类被称为外部类. (2).那为什么要将一个类定 ...

  5. Java中的内部类怎么用

    一.为什么需要内部类?java内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时 ...

  6. Java中的内部类(回调)

    一.内部类的主要作用如下: 1. 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类 2. 内部类的方法可以直接访问外部类的所有数据,包括私有的数据 3. 内部类所 ...

  7. 【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 ...

  8. Java中的内部类————以及jdk1.8的lambda表达式

    一.内部类学习导图 1>.静态内部类: 使用static修饰符来修饰内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象.因此使用static修饰的内部类被称为静态内部类. publi ...

  9. Java基础(十五):Java 中的内部类

    问:什么是内部类呢? 答:内部类( Inner Class )就是定义在另外一个类里面的类.与之对应,包含内部类的类被称为外部类. 问:那为什么要将一个类定义在另一个类里面呢?清清爽爽的独立的一个类多 ...

随机推荐

  1. javaScript系列 [01]-javaScript函数基础

    [01]-javaScript函数基础 1.1 函数的创建和结构 函数的定义:函数是JavaScript的基础模块单元,包含一组语句,用于代码复用.信息隐蔽和组合调用. 函数的创建:在javaScri ...

  2. 用DirectX实现多视图渲染

    什么是多视图 一般的3D程序都只有一个视图,对应整个窗口的客户区.多视图就是在一个窗口中放置多个视图,以便从不同的角度观察模型或者场景.很多图形软件都有这个功能,比如大家熟知的3DMax就有四个视图, ...

  3. ABAP语言实现 左移 <<、无符号右移 >>> 位移操作

    这几天要在ABAP中实现 3DES 标准对称加密算法,与其他外部系统进行加密/解密操作.由于ABAP语言中没有 左移 <<.无符号右移 >>>  操作,只能自己实现 思路 ...

  4. idea java9以及以上 出现找不到class的情况

    https://juejin.im/entry/59cdb7e65188255d3448fc64 https://blog.jetbrains.com/idea/2017/03/support-for ...

  5. 使用 GeoIP2 获取 IP 的地理位置

    1. 准备工作 数据库 : 解析 IP 地理位置的的数据库来自 GeoLite2 开源数据库:https://dev.maxmind.com/geoip/geoip2/geolite2/ . C 语言 ...

  6. Vue $emit()不触发方法的原因

    vue使用$emit时,父组件无法触发监听事件的原因是: $emit传入的事件名称只能使用小写,不能使用大写的驼峰规则命名

  7. Redis 分布式锁的实现

    0X00 测试环境 CentOS 6.6 + Redis 3.2.10 + PHP 7.0.7(+ phpredis 4.1.0) [root@localhost ~]# cat /etc/issue ...

  8. (转)创建Windows服务(Windows Services)N种方式总结

    转自:http://www.cnblogs.com/aierong/archive/2012/05/28/2521409.html 最近由于工作需要,写了一些windows服务程序,有一些经验,我现在 ...

  9. Protocol Buffers学习教程

    最近看公司代码的过程中,看到了很多proto后缀的文件,这是个啥玩意?问了大佬,原来这是Protocol Buffers! 这玩意是干啥的?查完资料才知道,又是谷歌大佬推的开源组件,这玩意完全可以取代 ...

  10. Halcon中模板匹配方法的总结归纳

    基于组件的模板匹配: 应用场合:组件匹配是形状匹配的扩展,但不支持大小缩放匹配,一般用于多个对象(工件)定位的场合. 算法步骤: 1.获取组件模型里的初始控件 gen_initial_componen ...