概述
把类定义在另一个类的内部,该类就被称为内部类
。
- 访问权限
- 内部类可以直接访问外部类的成员,包括私有。
- 外部类要想访问内部类成员,必须创建对象。
class Outer {
private int num = 10;
class Inner {
public void show() {
System.out.println(num);
}
}
public void method() {
//找不到符号
//show();
Inner i = new Inner();
i.show();
}
}
class InnerClassDemo {
public static void main(String[] args) {
}
}
- 分类
成员内部类
:在成员位置定义的类局部内部类
:在局部位置定义的类匿名内部类
局部内部类与匿名内部类区别在于:局部内部类可以编写自己的构造方法。
成员内部类
- 成员内部类不是静态的:
外部类名.内部类名 对象名 = new 外部类名.new 内部类名();
- 成员内部类是静态的:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
class Outer {
//静态内部类访问的外部类数据必须用静态修饰。
private static int num = 10;
private int num2 = 20;
public static class Inner {
public void show() {
System.out.println(num);
}
}
class Inner2 {
public void show() {
System.out.println(num2);
}
}
}
class InnerClassDemo3 {
public static void main(String[] args) {
//成员内部类不是静态的
Outer.Inner2 oi2 = new Outer().new Inner2();
oi2.show();
//成员内部类是静态的
Outer.Inner oi = new Outer.Inner();
oi.show();
}
}
输出:
20
10
一般情况,成员内部类用private、static修饰,private
:保证数据的安全性,static
:方便访问数据。
class Body {
private class Heart {
public void operator() {
System.out.println("心脏搭桥");
}
}
public void method() {
Heart h = new Heart();
h.operator();
}
}
Body b = new Body();
b.method();
输出:
心脏搭桥
局部内部类
- 可以直接访问外部类的成员
- 在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能。
class Outer {
private int num = 10;
public void method() {
//int num2 = 20;
//final int num2 = 20;
class Inner {
public void show() {
System.out.println(num);
//从内部类中访问本地变量num2; 需要被声明为最终类型
System.out.println(num2);//20
}
}
//System.out.println(num2);
Inner i = new Inner();
i.show();
}
}
class InnerClassDemo5 {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
局部内部类访问局部变量的注意事项?
答:局部内部类访问的局部变量必须用final
修饰。
因为局部变量是随着方法的调用而调用,随着调用完毕而消失。而堆内存的内容并不会立即消失。 如果内部类使用的局部变量清空,而自身堆内存还在使用,会导致不可预知错误。所以,使用final修饰局部变量,这个变量就成了常量。不影响内部类继续使用。
匿名内部类
内部类的简化写法。本质是一个继承了该类或者实现了该接口的子类匿名对象。简化类定义。
格式:
new 类名或者接口名(){
重写方法;
}
class Outer {
public void method() {
//一个方法的时候
/*
new Inter() {
public void show() {
System.out.println("show");
}
}.show();
*/
//二个方法的时候
/*
new Inter() {
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show();
new Inter() {
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
}.show2();
*/
//如果很多个方法,就很麻烦了。可以使用临时引用调用。
Inter i = new Inter() { //多态
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
class InnerClassDemo6 {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
输出:
show
show2
一般,匿名内部类在开发中的使用是作为参数传入
interface Person {
public abstract void study();
}
class PersonDemo {
//接口名作为形式参数
//其实这里需要的不是接口,而是该接口的实现类的对象
public void method(Person p) {
p.study();
}
}
//实现类
class Student implements Person {
public void study() {
System.out.println("好好学习,天天向上");
}
}
class InnerClassTest2 {
public static void main(String[] args) {
//测试
PersonDemo pd = new PersonDemo();
Person p = new Student();
pd.method(p);
System.out.println("--------------------");
//匿名内部类在开发中的使用
//匿名内部类的本质是继承类或者实现了接口的子类匿名对象
pd.method(new Person(){
public void study() {
System.out.println("好好学习,天天向上");
}
});
}
}
面试题1:
要求请填空分别输出30,20,10。
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
//System.out.println(new Outer().num);
System.out.println(Outer.this.num);
}
}
}
class InnerClassTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
面试题2:
要求在控制台输出”HelloWorld”interface Inter {
void show();
}
class Outer {
//补齐代码
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
class Outer {
//补齐代码
public static Inter method() {
//子类对象 -- 子类匿名对象
return new Inter() {
public void show() {
System.out.println("HelloWorld");
}
};
}
}
Outer.method()
可以看出method()
是类 Outer 中的一个静态方法;Outer.method().show()
可以看出method()
方法的返回值是一个对象。又因为接口 Inter 中有一个 show() 方法,所以 method() 方法返回实现接口 Inter 的子类对象。
内部类的作用
1、内部类可以很好的实现隐藏
成员内部类用private、static修饰,private:保证数据的安全性,static:方便访问数据。
2、内部类可以访问外部类的所有属性
内部类拥有外围类的所有元素的访问权限
3、实现多重继承
个人认为它是内部类存在的最大理由之一。正是由于他的存在使得Java的继承机制更加完善。
Example1
:
public abstract class Example1 {
public abstract String name();
}
Example2
:
public abstract class Example2 {
public abstract int age();
}
MultiExample
:
public class MultiExample {
private class test1 extends Example1 {
@Override
public String name() {
return "shwen";
}
}
private class test2 extends Example2 {
@Override
public int age() {
return 29;
}
}
public String name() {
return new test1().name();
}
public int age() {
return new test2().age();
}
public static void main(String args[]) {
MultiExample mi = new MultiExample();
System.out.println("姓名:" + mi.name());
System.out.println("年龄:" + mi.age());
}
}
输出:
姓名:shwen
年龄:29
MultiExample
类包含内部类test1
、test12
,test1
类继承了Example1
,test2
类继承了Example2
,这样类MultiExample
就拥有了Example1
和Example2
的方法和属性,也就间接地实现了多继承。
4、区别继承的类和接口里同名方法
问题:Java是一门单继承语言,但是,在子类的继承关系中,会存在父类和接口有同名方法的情况,这种情况该怎么处理呢?
接口MyInterface
:
public interface MyInterface {
void test();
}
父类Father
:
public class Father {
public void test() {
System.out.println("父类方法");
}
}
public class Son extends Father implements MyInterface{}
子类没有重写接口方法test()
,但是不报错。因为,子类默认继承了父类test()
方法。
修改一:如果将父类test()
方法注释:
public class Father {
/*public void test() {
System.out.println("父类方法");
}*/
}
需要子类实现接口中的方法。
修改二:将父类中方法取消注释,子类实现该方法,代码如下:
public class Father {
public void test() {
System.out.println("父类方法");
}
}
public class Son extends Father implements MyInterface {
public void test() {
System.out.println("子类方法");
}
}
可以看到,子类方法提示是重写父类方法 并且 实现接口方法。
继承的类和接口里面有两个同名的方法,默认重写继承父类的方法,那如果想重写接口的方法呢?怎么区分它们??
答:内部类
public class Son extends Father {
public void test() {
System.out.println("子类继承方法");
}
class test1 implements MyInterface {
@Override
public void test() {
System.out.println("子类实现方法");
}
}
MyInterface getMyInterface() {
return new test1();
}
}
我们可以用内部类test1
来实现接口,这样就不会与外围类的方法冲突了。