四种权限修饰符
java有四种权限修饰符:public > protected > (default) > private
public | protected | default | private | |
同一个类 | yes | yes | yes | yes |
同一个包(同级) | yes | yes | yes | NO |
不同包的子类(继承) | yes | yes | NO | NO |
不同包,非子类(路人) | yes | NO | NO | NO |
Notice:(default) 并不是 default 关键字,而是成员变量 / 方法前什么也不写,例如:int num = 6;
内部类
一个物体内部可以包含另一个物体:那么一个类的内部也能包含另一个类,例如 电脑和CPU、汽车与发动机
内部类分为:成员内部类 和 局部内部类
1)成员内部
注意事项:
- 内用外,随便访问,外用内,需要通过内部类对象访问
- 使用成员内部类,有两种方式:
- 直接:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
- 间接:在外部类的方法中使用内部类,然后在 main 方法中调用外部类的方法
public class ExteriorClass { String str = "exterior"; public void exteriorMethod(){ System.out.println("exterior method execute"); // 外部类不能访问内部类成员变量 // System.out.println(inside); // 错误写法 System.out.println(new InsideClass().num); } public class InsideClass{ int num = 6; public void insideMethod(){ System.out.println("inside method execute"); // 内部类可以访问外部类成员变量 System.out.println(str); } } public static void main(String[] args) { ExteriorClass exterior = new ExteriorClass(); // 通过外部类方法 间接使用 内部类对象 exterior.exteriorMethod(); // exterior method execute 6 // 不能直接创建内部类 // InsideClass inside = new InsideClass(); // 错误写法 ExteriorClass.InsideClass inside = new ExteriorClass().new InsideClass(); inside.insideMethod(); // inside method execute exterior } }
2)局部内部类(包含匿名内部类)
定义在方法内部的,就是局部内部类;局部,就是只有在当前所属的方法中才能使用
public class Outer{ // 外部类方法 public void outerMethod(){ System.out.println("outer method execute"); // outer method execute // 局部内部类 class Inner{ int num = 6; // 内部类方法 public void innerMethod(){ System.out.println(num); } } // 在外部方法中 使用内部类 Inner inner = new Inner(); inner.innerMethod(); // 6 } public static void main(String[] args) { Outer outer = new Outer(); outer.outerMethod(); } }
注意事项:如果局部内部类对象需要用到方法的局部变量,那么这个局部变量必须是 final 修饰的;从 java 8+ 开始,关键字 final 可省略
原因:声明周期
- new出来的对象保存在 堆内存 中
- 局部变量在 栈内存 中
- 方法运行结束之后,出栈,局部变量会回收;但 new 出来的对象会持续在堆内存中,直到被回收,那么这时如果对象访问局部变量,就会出现问题,所以这里的局部变量是常量,会copy一份在堆内存中
public class OuterClass{ public void outerMethod(){ final String str = "johny"; // 局部变量 // str = "test"; // 错误写法 class Inner{ public void innerMethod(){ System.out.println(str); // johny } } Inner inner = new Inner(); inner.innerMethod(); } public static void main(String[] args){ OuterClass outer = new OuterClass(); outer.outerMethod(); } }
3)匿名内部类
如果接口的实现类(或者父类的子类)只需要使用唯一一次
那么这种情况下就可以省略该类的定义,使用匿名内部类
定义格式:
接口名称 对象名 = new 接口名称(){ @Override // 覆盖重写所有抽象方法 }; // new 代表创建对象的动作;接口名称就是匿名内部类需要实现的接口 // { ... } 才是匿名内部类的内容
demo:
// 接口 class interface MyInterface{ void method(); } // 外部类 public class DemoMain{ public static void main(String[] args){ // 按照常规的实现类来访问成员方法 // MyInterface obj = new MyInterfaceImpl(); // obj.method(); // 匿名内部类的写法 MyInterface obj = new MyInterface(){ @Override public void method(){ System.out.println("anonymity class method execute"); } }; // 使用匿名类对象访问成员方法 obj.method(); // anonymity class method execute // 匿名内部类 + 匿名对象的写法 new MyInterface(){ @Override public void method(){ System.out.println("anonymity object call method execute"); } }.method(); // anonymity object call method execute } }
注意事项:
- 匿名内部类,在创建对象时,只能使用一次,如果要多次创建对象,需要单独定义实现类
- 匿名对象,在调用方法时,只能调用一次
类作为成员变量 / 接口作为成员变量
用武器类、技能接口作为英雄对象的成员变量的例子:
// 英雄类 public class Hero { private String name; private Weapon weapon; // 类当做成员变量 private Skill skill; // 接口当做成员变量 public Hero(){ } public Hero(String name, Weapon weapon, Skill skill){ this.name = name; this.weapon = weapon; this.skill = skill; } public void attack(){ if (this.skill != null){ skill.use(); } } public void setName(String name) { this.name = name; } public void setWeapon(Weapon weapon) { this.weapon = weapon; } public void setSkill(Skill skill) { this.skill = skill; } public String getName() { return name; } public Weapon getWeapon() { return weapon; } public Skill getSkill() { return skill; } }
// 武器类 public class Weapon { private String code; public Weapon(){ } public Weapon(String code){ this.code = code; } public void setCode(String code) { this.code = code; } public String getCode() { return code; } }
// 技能接口 public interface Skill { void use(); }
// 技能实现类 public class SkillImpl implements Skill { @Override public void use() { System.out.println("施放技能攻击"); } }
// 主方法 public class DemoMain { public static void main(String[] args) { Hero hero = new Hero(); hero.setName("盖伦"); Weapon weapon = new Weapon(); weapon.setCode("AK-47"); hero.setWeapon(weapon); System.out.println("英雄的名字:" + hero.getName()); // 英雄的名字:盖伦 System.out.println("英雄的武器:" + hero.getWeapon().getCode()); // 英雄的武器:AK-47 // 设置英雄技能 hero.setSkill(new SkillImpl()); // 使用单独定义的实现类 hero.attack(); // 施放技能攻击 // 使用匿名内部类 Skill skill = new Skill() { @Override public void use() { System.out.println("内部类 施放技能攻击"); } }; hero.setSkill(skill); hero.attack(); // 内部类 施放技能攻击 // 使用匿名内部类 + 匿名对象 hero.setSkill(new Skill() { @Override public void use() { System.out.println("内部类 匿名对象 施放技能攻击"); } }); hero.attack(); // 内部类 匿名对象 施放技能攻击 } }
接口作为方法的参数与返回值
import java.util.ArrayList; import java.util.List; public class DemoInterface { public static void main(String[] args) { // List 是 实现类 ArrayList 的接口 List<String> list = new ArrayList<>(); List<String> result = addElement(list); for (int i = 0; i < result.size(); i++){ System.out.println(result.get(i)); // johny anson } } public static List<String> addElement(List<String> list){ list.add("johny"); list.add("anson"); return list; } }
后续在学习实践中再进行补充和完善。
ending ~