什么是内部类?

内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)。内部类主要有以下几类:内部、局部内部、静内部、匿名内部

内部类的共性

(1)、内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

(2)、内部类不能用普通的方式访问。

(3)、内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

(4)、外部类不能直接访问内部类的的成员,但可以通过内部类对象来访问

  内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。

  因为当某个外围类的对象创建内部类的对象时,此内部类会捕获一个隐式引用,它引用了实例化该内部对象的外围类对象。通过这个指针,可以访问外围类对象的全部状态。

通过反编译内部类的字节码,分析之后主要是通过以下几步做到的: 
  1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象的引用; 
  2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为1中添加的成员变量赋值; 
  3 在调用内部类的构造函数初始化内部类对象时, 会默认传入外部类的引用。

为什么需要内部类?

其主要原因有以下几点:

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

  • 内部类可以对同一个包中的其他类隐藏起来,一般的非内部类,是不允许有 private 与protected权限的,但内部类可以

  • 可以实现多重继承

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

使用内部类最吸引人的原因是:

  每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。大家都知道Java只能继承一个类,它的多重继承在我们没有学习内部类之前是用接口来实现的。但使用接口有时候有很多不方便的地方。比如我们实现一个接口就必须实现它里面的所有方法。而有了内部类就不一样了。它可以使我们的类继承多个具体类或抽象类。

成员内部类

即在一个类中直接定义的内部类, 成员内部类与普通的成员没什么区别,可以与普通成员一样进行修饰和限制。成员内部类不能含有static的变量和方法。

注意事项

1.实例内部类内部不允许定义任何静态内容

2.外部类静态方法中不能访问实例内部类数据

3.如果外部类成员变量、内部类成员变量、内部类方法中局部变量同名

class Cat{//外部类
private double weight;
public Cat(double weight) {
this.weight = weight;
}
class CatBody{//内部类
private String color;
public CatBody(String color) {
this.color = color;
}
public void show() {
//内部类 可以直接访问外部类的成员 Cat.this.weight
//内部类中 隐含了 一个外部类对象 Cat.this
System.out.println("颜色:"+color+","+weight);
}
}
public void display() {
System.out.println("重量:"+weight);
//颜色 外部类 访问 内部类的成员 用对象调用
CatBody body = new CatBody("白色");
body.show();
}
}
public class TestInner1 {
public static void main(String[] args) {
Cat cat = new Cat(33.3);
cat.display();
//必须 用 外部类 对象来 创建 内部类对象,属于 外部类对象的
Cat.CatBody body = cat.new CatBody("黑色");
body.show();
} }

局部内部类

在方法中定义的内部类称为局部内部类。与局部变量类似,局部内部类不能有访问说明符,因为它不是外围类的一部分,但是它可以访问当前代码块内的常量,和此外围类所有的成员。

注意事项

1.局部内部类不能声明静态成员

2.局部内部类处于静态方法中只能直接访问外部类静态成员

3.局部内部类处于实例方法中可以直接访问外部类静态成员和实例成员

4.局部内部类对局部变量的访问,JDK8.0之前只能访问final修饰的局部变量,8.0之后可以访问局部变量,但是局部变量的值不允许修改

public class TestInner2 {
static int ns = ;
int num = ; public void f() {
final int number = ;//8.0之前只能访问fianl
int number1 = ;
// number1 = 678;
class Inner{
//局部内部类 中不能声明静态成员,static final除外
static final int n = ;
public void show() {
System.out.println(ns);//直接访问外部类静态成员
System.out.println(num);//直接访问外部类实例成员
System.out.println(number);
//8.0之后 可以访问局部变量,但是局部变量的值不允许修改
System.out.println(number1);// }
}
}
public static void fs() {
class Inner{
//局部内部类 中不能声明静态成员,static final除外
static final int n = ;
public void show() {
System.out.println(ns);//直接访问外部类静态成员
System.out.println(new TestInner2().num);//对象访问
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub } }

静态内部类(嵌套类)

如果你不需要内部类对象与其外围类对象之间有联系,那你可以将内部类声明为static。这通常称为嵌套类(nested class)。想要理解static应用于内部类时的含义,你就必须记住,普通的内部类对象隐含地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时,就不是这样了。嵌套类意味着:

  1. 要创建嵌套类的对象,并不需要其外围类的对象。

  2. 不能从嵌套类的对象中访问非静态的外围类对象。

class School{
static class WaterFountain{
static int water = ;
public static void show() {
System.out.println(water);
}
int water1 = ;
public void show1() {
System.out.println(water1);
}
}
public void display() {
WaterFountain.show();//静态内部类中的静态成员,通过类名访问
WaterFountain w = new WaterFountain();
w.show1();//访问 非静态的成员 ,用静态内部类对象 调用
}
}
public class TestStaticInner1 { public static void main(String[] args) {
School s = new School();
s.display();
//创建 静态内部类对象
School.WaterFountain w = new School.WaterFountain();
w.show1();//非静态的
w.show();//静态的
School.WaterFountain.show();//静态
} }
 interface Info{
//public static
class InnerClass{
int x = ;
}
//public static
interface InnerInfo{
static void fs() {
System.out.println("fs_static");
}
default void fd() {
System.out.println("fd_default");
}
void fv();//abstract
}
}
class InfoImpl implements Info{
public void show() {
System.out.println(new InnerClass().x);
InnerInfo.fs();
//fd()
Info info = new InfoImpl();
Info.InnerInfo in = (Info.InnerInfo)info;
in.fd();
}
//---------定义内部类 实现 InnerInfo---------------
class InnerInfoImpl implements Info.InnerInfo{
@Override
public void fv() {
InnerInfo.fs();//调用 接口中的静态成员
fd();//调用 接口中的 默认方法
}
}
}
//顶级类 实现 InnerInfo内部接口
class InnerInfoImpl1 implements Info.InnerInfo{
@Override
public void fv() {
Info.InnerInfo.fs();//访问 静态成员
fd(); }
}
public class TestStaticInner2 { public static void main(String[] args) {
// TODO Auto-generated method stub } }

匿名内部类

匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:

  • 只用到类的一个实例。
  • 类在定义后马上用到。
  • 类非常小(SUN推荐是在4行代码以下)
  • 给类命名并不会导致你的代码更容易被理解。
class Base{
public void f() { }
}
/*class Sub extends Base{
public void f() {
System.out.println("sub");
}
}*/
class Demo{
//成员
Base base1 = new Base() {
//不能定义构造方法,但是能定义构造块
{
System.out.println("我是一个构造块");
} public void func() {}//自己独特的调用不到
static final int x = ;
public void f() {
System.out.println("sub");
}
}; public void show() {
new Base() {
public void f() {
System.out.println("sub");
}
public void func() {}
}.func();
}
}
public class TestInner1 {
public static void main(String[] args) {
Demo demo = new Demo();
demo.base1.f();
// demo.base1.func();//调用不到 /*Sub sub = new Sub();
sub.f();*/
//创建的是子类对象 } }

注意事项

1.必须实现一个类或一个接口

2.不能定义静态数据

3.不能定义构造器,能定义构造块

4.不能是抽象的,必须要实现所有的抽象方法

5.传参问题,可以传参

6.同名问题

Lambda表达式

函数式接口

接口中只定义了一个抽象方法。

interface La{
void func();
}

Lambda与匿名内部类的区别

1.Lambda只能实现函数式接口,匿名内部类可以实现接口、可以继承类

2.匿名内部类可以调用默认方法,Lambda不能调用默认方法

@FunctionalInterface
interface La{
void f();
}
/*class LaImpl implements La{
@Override
public void f() {
System.out.println("f");
} }*/
public class TestLa1 {
/* La la = new La() {
public void f() {
System.out.println("f");
}
};*/
//Lambda表达式
La la = ()->System.out.println("f");
public static void main(String[] args) { TestLa1 t = new TestLa1();
t.la.f();
/* TestLa1 t = new TestLa1();
t.la.f();*/ /*LaImpl la = new LaImpl();
la.f();*/ } }
 //函数式接口
interface La1{
// void f();//1.无参 无返回值
// int f();//2.无参 ,带返回值
// void f(int n);//3。带参 ,不带返回值
int f(int n1,int n2);
default void s() {}
}
//Lambda
class La1Impl{
//1.无参 无返回值------------------------------
/* La1 la1 = ()->{System.out.println("f");};
//方法体中只有一行代码,可以省略{}
La1 la2 = ()->System.out.println("f");*/
//2.无参 ,带返回值-------------------------------
/* La1 la3 = ()->{return 22;};
//只有 一条 return语句 可以省略掉 {} 和 return;
La1 la4 = ()->22;*/
//3。带参 ,不带返回值------------------------
/* La1 la5 = (m)->{System.out.println("结果:"+m);};
//只有 一个参数 可以省略()
La1 la6 = m ->System.out.println("结果:"+m);*/
//
La1 la7 = (n1,n2)->{return n1+n2;};
La1 la8 = (n1,n2)->n1+n2; }
public class TestLa2 { public static void main(String[] args) {
La1Impl la = new La1Impl();
// la.la1.f(); } }

方法引用

使用前提:Lambda中只有一条语句而且只引用了一个方法

作用:替换Lambda的语法,更加简洁。

类方法、对象方法、类型方法、构造方法

Day11 Java内部类的更多相关文章

  1. Java内部类final语义实现

    本文描述在java内部类中,经常会引用外部类的变量信息.但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索.本文从字节码层描述在内部类中是如何实现这些语义的. 本地临时变量 基本类型 fi ...

  2. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  3. 黑马----JAVA内部类

    黑马程序员:Java培训.Android培训.iOS培训..Net培训 黑马程序员--JAVA内部类 一.内部类分为显式内部类和匿名内部类. 二.显式内部类 1.即显式声明的内部类,它有类名. 2.显 ...

  4. java 内部类 *** 最爱那水货

    注: 转载于http://blog.csdn.net/jiangxinyu/article/details/8177326 Java语言允许在类中再定义类,这种在其它类内部定义的类就叫内部类.内部类又 ...

  5. java内部类和匿名内部类

    内部类即是包含在类里面的又一个类. java内部类分为: 成员内部类.静态嵌套类.方法内部类.匿名内部类 . 内部类的共性 (1).内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.clas ...

  6. Java内部类小程序(成员内部类,静态内部类,匿名内部类)

    /** * 测试java内部类(成员内部类,静态内部类,匿名内部类) * 局部内部类不常用,就不写了. * @package :java05 * @author shaobn * @Describe ...

  7. [转] Java内部类详解

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  8. java内部类的作用分析

    提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比.内部类从表面上看,就 ...

  9. 9)Java内部类(Inner Class)

      内部类:不可以有静态数据,静态方法或者又一个静态内部类      内部类的优点:隐藏类的细节,内部类可以声明为私有.内部类可以访问外部类的对象(包括private) 静态内部类:可以有静态数据,静 ...

随机推荐

  1. C#设计模式--模板方法模式(学习Learning hard 设计模式笔记)

    class Program { static void Main(string[] args) { //创建一个菠菜实例并调用模板方法 Spinach spinach = new Spinach(); ...

  2. MySQL的异步复制、全同步复制与半同步复制

    异步复制 异步复制,主库将事务 Binlog 事件写入到 Binlog 文件中,此时主库只会通知一下 Dump 线程发送这些新的 Binlog,然后主库就会继续处理提交操作,而此时不会保证这些 Bin ...

  3. Code Signal_练习题_reverseParentheses

    You have a string s that consists of English letters, punctuation marks, whitespace characters, and ...

  4. vue2.0 element-ui中input的@keyup.native.enter='onQuery'回车查询刷新整个表单的解决办法

    项目中用的element-ui是v1.4.3版本 实现的功能是在input中输入查询的名称,按下键盘回车键,可以查询表格中数据 问题是,我输入名称,按下回车,会整个表单刷新,搜索条件也被清空:代码如下 ...

  5. js/jq动态创建表格的行与列

    之前做了一个项目,需求是能动态创建表格行,动态创建表格的列,度了很多资料,都没有动态创建列的插件,所以自己动手写了一个 需求大概是(下图) 1.动态添加一行.2.动态添加一列,3.删除行.4.删除列, ...

  6. DOM增删改操作

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  7. maven 编译打包时,明明类文件没有问题,却提示错误:未结束的字符串字面值,maven-compiler-plugin:2.3.2

    maven错误提示如下: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (de ...

  8. 神奇的负Margin

    在做slide时候一般都是采用父元素超宽+overflow的做法,今天发现了用margin-right:-100%;可以让子元素全部重叠起来.效果也是不错的

  9. Oracle EBS AP更新供应商地址

    SELECT pvs.vendor_site_id, pvs.party_site_id, hps.party_site_name, hps.object_version_number, hps.pa ...

  10. [C# | WinCE | Solution] 在 WinCE 上访问 SSL 加密后的 WCF SOAP 服务接口出现“未能与远程服务器建立信任关系”

    Scenario: 服务器的 SOAP 使用了 GeoTrust 签名的 EV 证书,WinCE调用时出现“未能与远程服务器建立信任关系”的错误.原因是该 WinCE 设备信任的证书包括 Global ...