内部类
内部类就是一个类在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对于B类就是外部类了。
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类的定义格式:
修饰符 class 外部类名称{
修饰符 class 内部类名称{
// 。。。
}
// ...
}
例子1
package oop.demo07;
public class Outer {
private /*static*/ int id; /*这个static可以加可以不加*/
public void out(){
System.out.println("外部类的方法");
}
// 如果这个加一个static静态方法,情况就不一样了
// 下面的id就会出现错误。因为加了static后,程序会首先加载出来
// 没有声明的id,先出现肯定会报错,所以static应该加在上面的id上,那个先加载
// 在class类里面的class就叫内部类
// 成员内部类,四种修饰符中都可能写
public /*static*/ class Inner{
// 这个是内部类。这个叫成员内部类
public void in(){
System.out.println("这是内部类的方法");
}
// 内部类也可以哦获取外部类的私有属性
public void getId(){
System.out.println(id);
}
}
}
class A{
// 这个在整个类的外面的类,java中可以有多个这样的class类。
// 但是只能有一个public class 类
public static void main(String[] args) {
}
}
- 在class类里面的class就叫内部类
- 如果添加static的修饰符,那么先加载出那个属性或者方法。之所以报错就是因为是先加载的原因,导致没出生就有了。
- 想要调用内部类里面的方法,肯定和之前一样通过实例化类,肯定是实例化内部类
又因为在里面,所以通过外面类的引用调用
package oop.demo07;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
// 通过这个外部类来实实例化内部类
// 想要调用内部类里面的方法,肯定和之前一样通过实例化类,这里肯定是实例化内部类
// 又因为在里面,所以通过外面类的引用调用
Outer.Inner inner = outer.new Inner();
inner.in(); // 这是内部类的方法
// 内部类里面调用外部类中的私有属性,所以
inner.getId();
}
}
例子2
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能使用了。
小结一下类的权限修饰符:
public > protected > (default) > private
定义一个类的时候,权限修饰规则:
- 外部类:public / (default)
- 成员内部类:public / protected / (default) / private
- 局部内部类:什么都不用写.
package oop.demo07;
public class Outer {
// 局部内部类
public void method(){
// 局部内部类:定义在方法里面的内部类叫局部内部类
// 局部内部类,不用写修饰符,直接class 局部内部类名
class Inner{
public void in(){
}
}
}
}
package oop.demo07;
public class Application {
public static void main(String[] args) {
// Apple apple = new Apple();
// 实例化Apple类得到的引用apple,是这个类对象的赋值。
new Apple().eat(); // 这个叫做匿名初始化类,不用将实例保存到变量侯总
// 本来接口是不能直接new的,但是如果要new只能使用匿名类,然后重写方法
UserService userService = new UserService() {
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("其中一个类的成员方法");
}
}
interface UserService{
void hello();
}
匿名内部类
匿名内部类:如果接口的实现类(或者是父类的子类)只需要使用唯一的一次。那么这种情况下就可以省略掉该类的定义,而改为【匿名内部类】
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称(){
// 覆盖重写所有的抽象方法
}
匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了[对象名称]
强调:匿名内部类和匿名对象不是一回事!!!
匿名内部类相当于是替代那个接口的实现类的
public static void main(String[] args) {
// 创建实现类 前面是接口名 对象名 = new 实现类名
/*MyInterface impl = new MyInterfaceImpl();
impl.method1(); */ //覆盖重写了方法1
//使用多态的写法 左父右子,左边写接口对象
/* MyInterface obj = new MyInterfaceImpl();
obj.method1();*/ //覆盖重写了方法1
// 错误写法,不能直接new接口,而是要new实现类
// MyInterface some = new MyInterface();
// 使用匿名内部类,但是不是匿名对象,对象的名称就叫objA
MyInterface objA = new MyInterface() {
@Override
public void method1() {
System.out.println("匿名内部类实现了方法1aaa");
}
@Override
public void method2() {
System.out.println("匿名内部类是实现类方法2BBB");
}
};
// 接口名后面的属于匿名内部类,
objA.method1(); //匿名内部类实现了方法1aaa
objA.method2(); // 匿名内部类是实现类方法2BBB
System.out.println("======");
// 使用了匿名内部类,而且省略了对象名称,也是匿名对象
new MyInterface(){
@Override
public void method1(){
System.out.println("匿名内部类实现了方法111-BBB");
}
@Override
public void method2(){
System.out.println("匿名内部类实现了方法!222-BBB");
}
}.method1(); // 因为没有名字所以,在匿名对象直接点.方法
// 并且匿名对象是无法调用第二次方法,所以需要再创建一个匿名内部类的匿名对象
new MyInterface(){
@Override
public void method1() {
System.out.println("匿名内部类实现了方法111-BBB");
}
@Override
public void method2() {
System.out.println("匿名内部类实现了方法!222-BBB");
}
}.method2();
}
类和接口都可以用作成员变量名