1.内部类的定义
内部类是指在一个外部类的内部再定义一个类。
内部类可以是静态static的,也可用public,default,protected,private修饰。(而外部顶级类即类名和文件名相同的只能使用public和default)。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。
2.成员内部类
成员内部类,就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法。则需要通过内部类的对象来获取。
要注意的是,成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。
package com.njwb.innerclass.use01;
public class Outer1 {
public int num1 = 10;
private int num2 = 33;
public void onlyTest(){
System.out.println("HelloWorld");
}
private int addNum(int a,int b){
return a+b;
}
public class Inner{
public int num1 = 20;
//成员内部类中不能出现static变量,static方法
//private static int num3 = 21;
/*private static void ceshi(){
}*/
public void onlyTest(){
System.out.println("Hello,tom");
}
public void print(){
System.out.println("num1="+num1);//内部类的成员变量(属性)和外部类同名时,内部类的成员变量有更高的优先级
System.out.println("访问外部类的私有变量"+"num2="+num2);//内部类可以任意访问外部类的属性,即使是私有的,也可以访问
System.out.println("调用外部类的私有访方法:"+addNum(11,11));
}
}
public Inner getInner(){
return new Inner();
}
public static void main(String[] args) {
//创建外部类对象
Outer1 out = new Outer1();
System.out.println(out.num1);
out.onlyTest();
System.out.println("-----------------");
//有内部类的对象才可以 内部类对象,借助外部类生成
//Inner in = out.new Inner(); //方式1
Inner in = out.getInner(); //方式2
//Inner in = new Inner(); //错误的
//想访问内部类的属性
System.out.println(in.num1);
//想调用内部类的方法
in.onlyTest();
//变量同名时,调用的是内部类的变量
in.print();
}
}
3.局部内部类
局部内部类,是指内部类定义在方法和作用域(语句块中)内。
局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
方法内部类也有两个特点:
(1) 方法中的内部类没有访问修饰符,即方法内部类对包围它的方法之外的任何东西都不可见。
(2)方法内部类能够访问该方法中的局部变量,所以也叫局部内部类。而且这些局部变量一定要是final修饰的常量(访问的变量分为2类,1个是本方法中,1个是外部类中)。
例题1:
package com.njwb.innerclass.use01;
/**
* 局部内部类 版本1 ,定义在方法中的类
* @author Administrator
*
*/
interface Destination{
}
public class Outer2 {
public Destination generateDestination(){
//定义在方法内部的类 ,只在本方法内有效,超出本方法,对于外界不可见(外界访问不到)
class PDestination implements Destination{
private String label="hello";
public String readLabel(){
return this.label;
}
}
//创建内部类对象
PDestination d = new PDestination();
//调用内部类的方法
System.out.println(d.readLabel());
return d;
}
public void ceshi(){
//创建内部类对象
//PDestination d = new PDestination();
}
public static void main(String[] args) {
Outer2 out = new Outer2();
Destination d = out.generateDestination();
}
}
例题2:
package com.njwb.innerclass.use01;
/**
* 局部内部类 ,定义在作用域中(语句块)
* @author Administrator
*
*/
public class Outer3 {
public void ceshi(boolean flag){
if(flag){
//int num=10;
//在if作用域内创建1个类,只在if作用域内有效,其他地方都访问不到,即使本方法
class Inner{
private String label="hello";
public String readLabel(){
return label;
}
}
Inner in = new Inner();
System.out.println(in.readLabel());
}else{
System.out.println("flag="+flag);
//System.out.println("num="+num); //else中访问不到if中num变量
//Inner in2 = new Inner(); //同样道理
}
//System.out.println("num="+num); //本方法中也访问不到if中num变量
}
public static void main(String[] args) {
Outer3 out = new Outer3();
out.ceshi(true);
}
}
例题3:
package com.njwb.innerclass.use01;
/**
* 定义在方法中的局部内部类 ,局部内部类可以访问的变量的类型?
* 1.如果访问本方法中的变量,该变量必须是final修饰的常量
* 2.如果访问外部类中的变量,该变量的类型不限制
* @author Administrator
*
*/
public class Outer4 {
private int num2 = 33;
private static int num3 = 34;
public void ceshi(){
final int num1 = 12; //该变量必须用final修饰
class Inner{
public void printStr(){
System.out.println("num1="+num1);
System.out.println("num2="+num2);
System.out.println("num3="+num3);
}
}
//实例化内部类对象,调用内部类的方法
Inner in = new Inner();
in.printStr();
}
public static void main(String[] args) {
Outer4 out = new Outer4();
out.ceshi();
}
}
4.静态内部类
就是修饰为static的内部类。声明为static的内部类,不需要内部类对象和外部类对象之间的联系,就是说我们可以直接引用Outer.Inner,即不需要创建外部类对象,也不需要创建内部类对象。
静态内部类和普通的成员内部类还有一个区别:普通内部类不能有static属性和static方法,但静态内部类可以。静态内部类一般声明为public,方便调用。
静态内部类和普通的成员内部类最大的区别:静态内部类中无法引用到其外围类的非静态成员(既包含外部类的 成员变量,也包含外部类的成员方法)。
package com.njwb.innerclass.use02;
/**
* 静态内部类: 可以出现静态的变量,静态的方法 ,普通内部类不可以
* 1.静态内部类 不能访问外部类的非静态的成员(变量,方法)
* 2.静态内部类的静态方法 外部类的类名.内部类的类名.内部类的方法名
* 3.如果静态内部类中出现的普通方法,该如何调用? 在 Outer1中 定义一个方法 返回该内部类对象 public Inner getInner(){}
* 在测试中main方法中 ,通过Outer1 out = new Outer1(); 先获取到外部类的对象,再调用getInner()方法,获取到内部类对象
* @author Administrator
*
*/
public class Outer1 {
private int num2 = 20;
private static int num3 = 30;
public void ceshi1(){
System.out.println("测试1");
}
public static void ceshi2(){
System.out.println("测试2");
}
public static class Inner{
public static int num1=10;
public static void printStr(){
System.out.println("hello");
//静态内部类不能引用外部类的 非静态变量
//System.out.println("num2="+num2);
System.out.println("num3="+num3);
//静态内部类中调用外部类的方法 ,不能引用外部类的非静态方法
//ceshi1();
ceshi2();
}
public void innerCommonMethod(){
System.out.println("静态内部类Inner中定义的普通方法innerCommonMethod()");
}
}
public Inner getInner(){
return new Inner();
}
public static void main(String[] args) {
//调用静态内部类的方法
Outer1.Inner.printStr();
Outer1 out = new Outer1();
//获取到内部类的对象
Inner in = out.getInner();
//调用内部类的普通方法
in.innerCommonMethod();
}
}
4.匿名内部类
匿名内部类是不能加访问修饰符的。要注意的是,new 匿名类,这个类是要先定义的。
4.1.匿名内部类不带参数(掌握)
留意外部类的方法的形参,当所在的方法的形参需要被内部类里面使用时,该形参必须为final.
package com.njwb.innerclass.use02;
interface Inner21{
String getName();
}
public class Outer21 {
/**
* name被内部类使用的,用final修饰 ,city没有被内部类使用,不用final修饰
* @param name
* @param city
* @return
*/
public Inner21 getInner(final String name,String city){
class MyInner implements Inner21{
private String label = name;
@Override
public String getName() {
return label;
}
}
return new MyInner();
}
}
package com.njwb.innerclass.use02;
/**
* 不带参的匿名内部类 和Outer21中的效果完全等价
* 匿名内部类 :没有具体的类名,不加访问修饰符,以前所有放在类体里,都需要放在 匿名的那个类的花括号中{}
* @author Administrator
*
*/
interface Inner22{
String getName();
}
public class Outer22 {
/**
* name被内部类使用的,用final修饰 ,city没有被内部类使用,不用final修饰
* @param name
* @param city
* @return
*/
public Inner22 getInner(final String name,String city){
return new Inner22(){
private String label = name;
@Override
public String getName() {
return label;
}
};
}
}
这里可以看到形参name已经定义为final了,而形参city没有被使用则不用定义为final.
4.2匿名内部类带参数(掌握)
package com.njwb.innerclass.use02;
abstract class Inner31{
public Inner31(String name,String city) {
}
public Inner31() {
}
abstract String getName();
}
public class Outer31 {
public Inner31 getInner(String name,String city){
class MyInner extends Inner31{
private String label;
public MyInner(String name0,String city0) {
this.label = name0;
}
@Override
String getName() {
return label;
}
}
return new MyInner(name,city);
}
public static void main(String[] args) {
Outer31 out = new Outer31();
Inner31 in = out.getInner("jack", "nanjing");
System.out.println(in.getName());
}
}
package com.njwb.innerclass.use02;
abstract class Inner32{
public Inner32(String name,String city) {
}
abstract String getName();
}
public class Outer32 {
public Inner32 getInner(final String name,String city){
return new Inner32(name,city){
private String label=name;
@Override
String getName() {
return label;
}
};
}
}
注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final
4.3匿名内部类通过实例初始化,可以达到类似构造器的效果
package com.njwb.innerclass.use02;
interface Inner41{
String getName();
String getCity();
}
public class Outer41 {
public Inner41 getInner(final String name,final String city){
class MyInner implements Inner41{
private String nameStr = name;
private String cityStr = city;
@Override
public String getCity() {
return cityStr;
}
@Override
public String getName() {
return nameStr;
}
}
return new MyInner();
}
public static void main(String[] args) {
Outer41 out = new Outer41();
//类似带参构造传入2个参数 类似 Inner41 in = new Inner41("jack","南京");
Inner41 in = out.getInner("jack", "南京");
//通过get方法获取属性的值 ,实质上也不是真正的get访问器,而是接口中定义的带返回值的抽象方法
System.out.println(in.getName());
System.out.println(in.getCity());
}
}
package com.njwb.innerclass.use02;
interface Inner42{
String getName();
String getCity();
}
public class Outer42 {
public Inner42 getInner(final String name,final String city){
return new Inner42(){
private String nameStr = name;
private String cityStr = city;
@Override
public String getCity() {
return cityStr;
}
@Override
public String getName() {
return nameStr;
}
};
}
public static void main(String[] args) {
Outer42 out = new Outer42();
Inner42 in = out.getInner("jack", "南京");
System.out.println(in.getName());
System.out.println(in.getCity());
}
}
5.内部类的继承(了解)
内部类的继承,是指内部类被继承,普通类extends 内部类。而这时候代码上要有点特别处理。
package com.njwb.innerclass.use02;
/**
* 内部类的继承 ,内部类可以是其他的类的父类
* @author Administrator
*
*/
class WithInner{
class Inner{
}
}
//父类为内部类Inner
class InheritInner extends WithInner.Inner{
//如果一个类继承了内部类,那么该类必须定义带参构造,参数必须传入内部类所在的外部类的对象
public InheritInner(WithInner wi) {
wi.super();
}
}
public class Outer5 {
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner in = new InheritInner(wi);
}
}
可以看到子类的构造函数里面要使用父类的外部类对象.super();而这个对象需要从外面创建并传给形参。
内部类的特点总结
(1) 在方法间定义的非静态内部类:
l 外围类和内部类可互相访问自己的私有成员
l 内部类中不能定义静态成员
(2)在方法间定义的静态内部类:
l 只能访问外部类的静态成员。
(3)在方法中定义的局部内部类:
l 该内部类没有任何的访问控制权限
l 外围类看不见方法中的局部内部类的(局部内部类的作用域),但是局部内部类可以访问外围类的任何成员。
l 方法体中可以访问局部内部类,但是访问语句必须在定义局部内部类之后。
l 局部内部类可以访问方法体中的常量,即用final修饰的成员。
(4)在方法中定义的匿名内部类:
没有构造器,取而代之的是将构造器参数传递给超类构造器(匿名内部类创建的时候调用父类已经声明的带参构造器)。