稍复杂的成员变量类型

  • 类作为成员变量
  • 接口作为成员变量

类作为成员变量

如常见的定义成员变量:String str=“哈哈哈”,实际上String就是一个类,只不过是JDK作者写的。同样,我们也可以自定义一个类当作成员变量。

比如在游戏中,英雄是一个类,在设定英雄类的成员变量的时候,我们想给英雄配备一把武器。问题是其他英雄也要有武器,而且武器有很多参数,因此我们把武器也创建成一个类,武器类给不同的英雄类当成员变量使用,详见下例:

public class Hero {
    private String name; // 英雄名
    private int age;
    private Weapon weapon;

    public Hero() {
    }

    public Hero(String name, int age, Weapon weapon) {
        this.name = name;
        this.age = age;
        this.weapon = weapon;
    }

    public void attack() {
        System.out.println("年龄为" + age + "岁的" + name +
                "正在用" + weapon.getWeaponCode() + "攻击敌方!");
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Weapon getWeapon() {
        return weapon;
    }

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

    public void setAge(int age) {
        this.age = age;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }
}
public class Weapon {
    private String weaponCode;// 武器代号

    public Weapon() {
    }

    public Weapon(String weaponCode) {
        this.weaponCode = weaponCode;
    }

    public String getWeaponCode() {
        return weaponCode;
    }

    public void setWeaponCode(String weaponCode) {
        this.weaponCode = weaponCode;
    }
}
public class Demo {
    public static void main(String[] args) {
        Hero hero = new Hero();
        hero.setName("老亚瑟");
        hero.setAge(98);
        Weapon weapon = new Weapon("大宝剑");
        hero.setWeapon(weapon);
        hero.attack();
    }
}

// 年龄为98的老亚瑟正在用大宝剑攻击敌方!

接口作为成员变量

接口同样可以作为类的成员变量

// 这是新定义的接口:Skill
public interface Skill {
    void use();
}

以上面的英雄例子为基础做一些添加:

  1. 加入一个成员变量:技能Skill,这是一个接口类型
  2. 在英雄的方法attack()中,加入关于技能的调用 skill.use()
  3. 对全参构造方法、getter/setter做相应调整
public class Hero {
    private String name; // 英雄名
    private int age;
    private Weapon weapon;
    private Skill skill;// 英雄的技能


    public Hero() {
    }

    public Hero(String name, int age, Weapon weapon, Skill skill) {
        this.name = name;
        this.age = age;
        this.weapon = weapon;
        this.skill = skill;
    }

    public void attack() {
        System.out.print("年龄为" + age + "岁的" + name +
                "正在用" + weapon.getWeaponCode() + "攻击敌方并使用了技能:");
        skill.use(); // 调用接口中的抽象方法

    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Weapon getWeapon() {
        return weapon;
    }

    public Skill getSkill() {
        return skill;
    }

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

    public void setAge(int age) {
        this.age = age;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }
}
public class Demo {
    public static void main(String[] args) {
        Hero hero = new Hero();
        hero.setName("[老亚瑟]");
        hero.setAge(98);
        Weapon weapon = new Weapon("[大宝剑]");
        hero.setWeapon(weapon);

        hero.setSkill(new SkillImpl());// 写法1:使用单独定义的实现类,SkillImpl为此而生
        hero.attack();

        Skill skill2 = new Skill() {// 写法2:使用匿名内部类
            @Override
            public void use() {
                System.out.println("[回旋打击]");
            }
        };
        hero.setSkill(skill2);
        hero.attack();

        hero.setSkill(new Skill() {// 写法3:使用匿名内部类、匿名对象
            @Override
            public void use() {
                System.out.println("[誓约之盾]");
            }
        });
        hero.attack();
    }
}

/*
年龄为98岁的[老亚瑟]正在用[大宝剑]攻击敌方并使用了技能:[圣剑裁决]
年龄为98岁的[老亚瑟]正在用[大宝剑]攻击敌方并使用了技能:[回旋打击]
年龄为98岁的[老亚瑟]正在用[大宝剑]攻击敌方并使用了技能:[誓约之盾]
*/

对于上面的写法1,由于没有使用匿名内部类,因此需要创建一个实现类SkillImpl如下:

public class SkillImpl implements Skill {
    @Override
    public void use() {
        System.out.println("[圣剑裁决]");
    }
}

上面的代码块作为实现类,即对接口中use()方法的一个简单重写。main方法中就可以用本实现类new出一个对象(本例中这一步实际上也是匿名对象),用Setter把这个对象传入到Hero类中,Hero的成员变量skill就得到了该实现类的对象,在attack()中调用SkillImpl中的use()方法输出了[圣剑裁决]。变量为接口,传入的却是实现类对象,相当于Skill skill=new SkillImpl,接口类型skill指向的是该接口的实现类,因此发生了向上转型。