1.内部类的概念与分类
如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一 个类。
例如:身体和心脏的关系。又如:汽车和发动机的关系。
分类:
- 成员内部类
- 局部内部类(包含匿名内部类)
2.成员内部类
2.1成员内部类的定义
成员内部类的定义格式:
修饰符class 外部类名称{
修饰符class 内部类名称{
// ...
}
// ...
}
注意:内用外,随意访问;外用内,需要内部类对象。
package cn.itcast.day10.demo05;
public class Body { //外部类
public class Heart{ //成员内部类
//内部类的方法
public void beat(){
System.out.println("小鹿乱撞");
}
}
//外部类的成员变量
private String name;
public void methodBody(){
System.out.println("外部类的方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.2成员内部类的使用
如何使用成员内部类——有两种方式:
- 间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
- 直接方式,公式: 外部类名称.内部类名称对象名= new外部类名称(). new内部类名称();
package cn.itcast.day10.demo05;
public class Body { //外部类
public class Heart{ //成员内部类
//内部类的方法
public void beat(){
System.out.println("小鹿乱撞");
System.out.println("我是内部类的方法");
}
}
//外部类的成员变量
private String name;
public void methodBody(){
System.out.println("外部类的方法");
new Heart().beat();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package cn.itcast.day10.demo05;
public class InnerClass {
public static void main(String[] args) {
Body body = new Body();
//通过外部类的对象,调用外部类的方法,里面间接在使用内部类Heart
body.methodBody();
System.out.println("=================");
Body.Heart body1 = new Body().new Heart();
body1.beat();
}
}
执行结果
外部类的方法
小鹿乱撞
我是内部类的方法
=================
小鹿乱撞
我是内部类的方法
2.3内部类的同名变量访问
如果出现了重名现象,那么格式是:外部类名称. this .外部类成员变量名。
package cn.itcast.day10.demo05;
public class Outer {
int num = 10; //外部类的成员变量
public class Inner{
int num = 20; //内部类的成员变量
public void methodInner(){
int num = 30; //内部类方法的局部变量
System.out.println(num); //局部变量,就近原则
System.out.println(this.num); //内部类的成员变量
System.out.println(Outer.this.num); //外部类的成员变量
}
}
}
主函数
package cn.itcast.day10.demo05;
public class InnerClass02 {
public static void main(String[] args) {
Outer.Inner a = new Outer().new Inner();
a.methodInner();
}
}
执行结果
30
20
10
3.局部内部类
3.1 局部内部类的定义
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
定义格式:
修饰符class 外部类名称{
修饰符返回值类型外部类方法名称(参数列表) {
class
局部内部类名称{
// ...
}
}
局部内部类
package cn.itcast.day10.demo05;
public class Outer03 {
public void methodOuter(){
class Inner{ //局部内部类
int num = 10;
public void methodInner(){
System.out.println(num);
}
}
Inner inner = new Inner();
inner.methodInner();
}
}
主函数
package cn.itcast.day10.demo05;
public class InnerClass03 {
public static void main(String[] args) {
Outer03 obj = new Outer03();
obj.methodOuter();
}
}
执行结果
10
小结一下类的权限修饰符:
public > protected > (default) > private
定义一个类的时候,权限修饰符规则:
- 外部类: public / (default)
- 成员内部类: public / protected / (default) / private
- 局部内部类:什么都不能写
3.2匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,而改为使用[匿名内部类。
匿名内部类的定义格式:
接口名称对象名= new接口名称() {
//覆盖重写所有抽象方法
};
接口
package cn.itcast.day10.demo06;
public interface MyInterface {
void method();
}
主函数
package cn.itcast.day10.demo06;
public class MyInterfaceNou {
public static void main(String[] args) {
MyInterface obj = new MyInterface() {
@Override
public void method() {
System.out.println("匿名内部类执行了");
}
};
obj.method();
}
}
执行结果
匿名内部类执行了
匿名内部类的注意事项
对格式“new接口名称() {…}"进行解析:
- new代表创建对象的动作
- 接口名称就是匿名內部类需要实现哪个接口
- {… }这才是匿名内部类的内容
另外还要注意几点问题:
- 匿名内部类,在[创建对象]的时候,只能使用唯一一次 。如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了。
- 匿名对象,在[调用方法]的时候,只能调用唯一次。如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
- 匿名内部类是省略了[实现类/子类名称],但是匿名对象是省略了[对象名称]
强调:匿名内部类和匿名对象不是一回事! ! !
接口
package cn.itcast.day10.demo06;
public interface MyInterface {
void methodA();
void methodB();
}
主函数
package cn.itcast.day10.demo06;
public class MyInterfaceNou {
public static void main(String[] args) {
//使用匿名内部类,但不是匿名对象,对象名称就叫obj
MyInterface obj = new MyInterface() {
@Override
public void methodA() {
System.out.println("匿名内部类执行了---AAA");
}
public void methodB() {
System.out.println("匿名内部类执行了---BBB");
}
};
obj.methodA();
obj.methodB();
System.out.println("=============");
//使用了匿名内部类,而且省略了对象名称,也是匿名对象
new MyInterface() {
@Override
public void methodA() {
System.out.println("匿名内部类执行了---CCC");
}
public void methodB() {
System.out.println("匿名内部类执行了---DDD");
}
}.methodA();
//因为匿名对象无法调用第二次方法,所以需要再创建一 个匿名内部类的匿名对象
new MyInterface() {
@Override
public void methodA() {
System.out.println("匿名内部类执行了---CCC");
}
public void methodB() {
System.out.println("匿名内部类执行了---DDD");
}
}.methodB();
}
}
执行结果
匿名内部类执行了---AAA
匿名内部类执行了---BBB
=============
匿名内部类执行了---CCC
匿名内部类执行了---DDD
4.类作为成员变量类型
思路:创建一个英雄类,自己写一个武器类,然后加入到英雄类里面,类似一个成员变量。
武器类
package cn.itcast.day10.demo07;
public class Weapon {
private String weaponName;
public Weapon() {
}
public Weapon(String weaponName) {
this.weaponName = weaponName;
}
public String getWeaponName() {
return weaponName;
}
public void setWeaponName(String weaponName) {
this.weaponName = weaponName;
}
}
英雄类
package cn.itcast.day10.demo07;
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.getWeaponName() + "攻击敌方");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}
主函数
package cn.itcast.day10.demo07;
public class HeroMain {
public static void main(String[] args) {
Hero hero = new Hero();
hero.setName("亚瑟");
hero.setAge(19);
//创建一个武器对象
Weapon weapon = new Weapon("极影之狼");
hero.setWeapon(weapon);
hero.attack();
}
}
执行结果
年龄为19的亚瑟用极影之狼攻击敌方
5.接口作为成员变量类型
思路:在英雄类里面添加一个技能,技能用接口完成,相当于接口作为成员变量类型。
技能接口
package cn.itcast.day10.demo08;
public interface Skill {
void use();//释放技能的抽象方法
}
英雄类
package cn.itcast.day10.demo08;
public class Hero {
private String name;
private Skill skill;
public Hero() {
}
public Hero(String name, Skill skill) {
this.name = name;
this.skill = skill;
}
public void attack(){
System.out.println(name +"开始释放技能");
skill.use();
System.out.println("释放技能完成");
}
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 cn.itcast.day10.demo08;
public class SkillMain {
public static void main(String[] args) {
Hero hero = new Hero();
hero.setName("露娜");
//匿名内部类实现
Skill skill = new Skill() {
@Override
public void use() {
System.out.println("月下无限连");
}
};
hero.setSkill(skill);
hero.attack();
System.out.println("============================");
//使用匿名内部类和匿名对象
Hero hero2 = new Hero();
hero2.setName("艾伦");
hero2.setSkill(new Skill() {
@Override
public void use() {
System.out.println("寒冰之剑");
}
});
hero2.attack();
}
}
执行结果
露娜开始释放技能
月下无限连
释放技能完成
============================
艾伦开始释放技能
寒冰之剑
释放技能完成
6.接口作为方法的参数和返回值
package cn.itcast.day10.demo08;
import java.util.ArrayList;
import java.util.List;
//java.util.List正是ArrayList所实现的接口
public class DemoInterface {
public static void main(String[] args) {
//左边是接口名称,右边是实现类名称,这就是多态写法
List<String> list = new ArrayList<>();
List<String> res = addNames(list);
for (int i = 0; i < res.size(); i++) {
System.out.println(res.get(i));
}
}
public static List<String> addNames(List<String> list){
list.add("乔丹");
list.add("科比");
list.add("詹姆斯");
list.add("韦德");
return list;
}
}