内部类

如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类

分类:

​ 1.成员内部类

​ 2.局部内部类(包含匿名内部类)

成员内部类

定义格式:

修饰符 class 外部类名称{

​ 修饰符 class 内部类名称{

}

}

注意:内用外随意,外用内,需要内部类对象

public class Body{//外部类
    public class Heart{//成员内部类

    }
}

如何使用成员内部类

1.间接方式:在外部类的方法当中,使用内部类,然后main只是调用外部类的方法。

2.直接方式:外部类名称 对象名 =new 外部类名称().new 内部类名称();

内部类的重名变量访问

public class Outer{
    int num=10;//外部类的成员变量
    public class Inner{
        int num=20;//内部类的成员变量
        public void methodInner(){
            int num=10;//内部方法的局部变量
            System.out.println(num);//局部变量,就近原则
            System.out.println(this.num);//毫无疑问是自己类的成员变量
            System.out.println(Out.this.num);//这么访问外部类的成员变量
        }
    }
}

局部内部类

类如果一个类定义在一个方法的内部,那么这就是一个局部内部类。

就是只有在当前所属的方法才能使用它,出了这个方法的外面就不能用了。

格式:

修饰符 class 外部类名称{

​ 修饰符 返回值类型 外部类方法名称(参数列表){

​ class 局部内部类名称{

}

}

}

public class Outer{
    public void methodOuter(){
        class Inner{//局部内部类
            int num=10;
            public void methodInner(){
                System.out.println("num");//10
            }
        }
         Inner inner =new Inner();//只有在methodOuter方法内才能使用
         inner.methodInner();
    }
}

public class Demo{
    public static void main(String [] args){
      Outer obj =new Outer();
        obj.methodOuter();
    }
}

局部内部类的final问题

局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的(可以是final修饰的,也可以是其他修饰但确实没有改变的)

public class MyOuter{
    public void methodOuter(){
        int num=10;//虽然为int,但确实没有改变,可以
        //final int num=10;也可以直接给这样写
        class MyInner{
            public void methodInner(){
                System.out.println(num);
            }
        }
    }
}

简述为什么保持不变的原因:

new出来的对象在堆内存中,局部变量是跟着方法走的,在栈内存当中,方法运行结束后,立刻出栈,局部变量跟着立刻消失,但是new出来的对象会在堆中持续存在,如果保证局部变量不变,局部内部类就可以复制一份局部变量跟随局部内部类对象,即使局部变量消失了,也能访问。

小节权限修饰符

public > protected > (default) > private

定义一个类时,权限修饰符规则:

1.外部类:public /(default)

2.成员内部类:public /protected/(default)/private

3.局部内部类:什么都不能写

匿名内部类

如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,使用匿名内部类。

定义格式:

接口名称 对象名 =new 接口名称(){

//覆盖重写所有抽象方法

};

//正常情况下
package text;
public interface MyInterface {
     void method();
}

package text;
public class MyInterfaceImpl implements MyInterface{
    @Override
    public void method() {
        System.out.println("实现类覆盖重写了方法!");
    }
}

package text;
public class Demo {
    public static void main(String[] args) {
        MyInterface impl =new MyInterfaceImpl();
        impl.method();
    }
}

//但是上述实现类只用了一次,可以考虑使用匿名内部类
package text;
public interface MyInterface {
     void method();
}

package text;
public class Demo {
    public static void main(String[] args) {
        MyInterface obj = new MyInterface() {//这个大括号包住的算是没有名字的类,这就叫做匿名内部类
            @Override
            public void method() {
                System.out.println("匿名内部类实现了方法!");
            }
        };
        obj.method();
    }
}

对格式"new 接口名称(){...}"进行解析:

1.new代表创建对象的动作

2.接口名称就是匿名内部类需要实现哪个接口

3.{...}这才是匿名内部类的内容

另外注意:

1.匿名内部类,在创建对象的时候,只能使用唯一的一次,如果希望使用多次,而且内容一样的话要么就写实现类,要么就重复写多次匿名内部类。

2.匿名对象,在调用方法时,只能调用唯一一次,如果希望同一个对象调用多次方法,那么必须给对象起个名字。

//综合匿名类和匿名对象
package text;
public interface MyInterface {
     void method1();
     void method2();
}

package text;
public class Demo {
    public static void main(String[] args) {
        new MyInterface(){
            @Override
            public void method1() {

            }
            @Override
            public void method2() {

            }
        }.method1();//只有new,没有对象,new完直接调用方法,既使用了匿名类也使用了匿名对象
    }
}

3.匿名内部类是省略了实现类或子类名称,但是匿名对象是省略了对象名称。

它俩不是一回事!!!

类作为成员变量

传的时候先new一个就行,其实String类型也是一个类,但是它不用new。

package Demo01;
public class Weapon {
    private String code;//武器的代号
    public Weapon(){
    }
    public Weapon(String code) {
        this.code = code;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
}

package Demo01;
public class Hero {
    private String name;//英雄名字
    private Weapon weapon;//英雄武器
    private int age;//
    public Hero() {
    }
    public Hero(String name, Weapon weapon, int age) {
        this.name = name;
        this.weapon = weapon;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Weapon getWeapon() {
        return weapon;
    }
    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

package Demo01;
public class Demo {
    public static void main(String[] args) {
        Hero hero =new Hero ();
        hero.setAge(20);
        hero.setName("德玛");
        Weapon weapon =new Weapon();
        weapon.setCode("无尽之刃");
        hero.setWeapon(weapon);
        System.out.println("一个"+hero.getAge()+ "岁的"+hero.getName()+"拿着"+weapon.getCode()+"击杀了敌方!");
    }
}

接口作为成员变量和成员方法

//公共
package Demo02;
public class Hero {
    private String name;
    private Skill skill;
    public void attack(){
        System.out.println("我叫"+name+",我放技能:");
        skill.use();
        System.out.println("技能施放结束!");
    }
    public Hero() {
    }
    public Hero(String name, Skill skill) {
        this.name = name;
        this.skill = skill;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Skill getSkill() {
        return skill;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }
}

package Demo02;
public interface Skill {
    void use();//施放技能的抽象方法
}

//方法一:正常实现类调用
package Demo02;
public class SkillImpl implements Skill{
    @Override
    public void use() {
        System.out.println("qqq");
    }
}
package Demo02;
public class Demo {
    public static void main(String[] args) {
        Hero hero =new Hero();
        hero.setName("锐雯");//设置英雄名称
        hero.setSkill(new SkillImpl());
        hero.attack();
    }
}

//方法二:使用匿名内部类
package Demo02;
public class Demo {
    public static void main(String[] args) {
        Hero hero =new Hero();
        Skill skill=new Skill() {
            @Override
            public void use() {
                System.out.println("qqq");
            }
        };
        hero.setSkill(skill);
        hero.attack();
    }
}

//方法三:再简单一点,同时使用匿名内部类和匿名对象
package Demo02;
public class Demo {
    public static void main(String[] args) {
        Hero hero =new Hero();
        hero.setName("锐雯");//设置英雄名称
        hero.setSkill(new Skill(){
            @Override
            public void use() {
                System.out.println("qqq");
            }
        });
        hero.attack();
    }
}

接口作为方法的参数

java.util.List正是ArrayList所实现的接口

import java.util.ArrayList;
import java.util.List;
public class Demo{
     public static void main(String[] args) {
         //左边是接口名称,右边是实现类名称,就是多态写法
         List<String> list =new ArrayList<>();
     }
    public static List<String> addNames(List<String> list){
        list.add("111");
        return list;
    }
}