概述
如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。
例如:身体和心脏的关系。又如:汽车和发动机的关系。
分类:
1. 成员内部类
2. 局部内部类(包含匿名内部类)
成员内部类的定义格式:
修饰符 class 外部类名称 {
修饰符 class 内部类名称 {
// ...
}
// ...
}
注意:内用外,随意访问;外用内,需要内部类对象。
==========================
成员内部类
如何使用成员内部类?有两种方式:
1. 间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。
2. 直接方式,公式:
类名称 对象名 = new 类名称();
【外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】
上代码
在外部类中定义内部类
public class Body {//外部类
public class Heart{//成员内部类
//内部类的方法
public void beat(){
System.out.println("我是内部类的方法");
//成员内部类中可以直接调用外部类中的成员变量
System.out.println("我的名字是"+name);
System.out.println("我的名字是"+getName());
}
}
private String name;//成员方法(外部类)
public Body() {//空参
}
public Body(String name) {//实参
this.name = name;
}
//外部类的方法
public void method(){
System.out.println("外部类方法");
//可以在外部类中创建内部类对象并调用内部类方法
// Heart heart = new Heart();
// heart.beat();
//或者直接匿名对象调用
new Heart().beat();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试
public class Demo01InnerClass {
public static void main(String[] args) {
//使用成员内部类:
//1、间接方式:通过外部类方法使用内部类
Body body = new Body();
body.method();
System.out.println("=============");
//2、直接方式:公式:【外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】
Body.Heart bh = new Body().new Heart();
bh.beat();
}
}
内部类的同名变量访问
创建类
//内部类方法中访问外部类成员变量:外部类名称.this.外部类成员变量
public class Outer {
int age = 10;//外部类成员变量
public class inter{
int age = 20;//内部类成员变量
public void methodAge(){//内部类成员方法
int age = 30;//内部类局部变量
System.out.println(age);//访问局部变量
System.out.println(this.age);//访问内部类成员变量
System.out.println(Outer.this.age);//访问外部类成员变量
}
}
}
测试类
public class Demo02InterClass {
public static void main(String[] args) {
//使用内部类
Outer.inter oi = new Outer().new inter();
oi.methodAge();
}
}
局部内部类
如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
定义格式:
修饰符 class 外部类名称 {
修饰符 返回值类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
// ...
}
}
}
小节一下类的权限修饰符:
public > protected > (default) > private
定义一个类的时候,权限修饰符规则:
1. 外部类:public / (default)
2. 成员内部类:public / protected / (default) / private
3. 局部内部类:什么都不能写
代码篇:
创建局部内部类:
public class Outer {
public void methodOuter(){
//局部内部类在方法中定义
System.out.println("外部类方法");
class Inter{
int age = 20;
public void methodInter(){
System.out.println("局部内部类方法"+age);
}
}
//局部内部类在方法中创建对象,并调用方法
Inter inter = new Inter();
inter.methodInter();
}
}
测试类
public class DemoMain {
public static void main(String[] args) {
Outer outer = new Outer();
outer.methodOuter();
}
}
局部内部类的final问题
创建类
public class MyOuter {
int age = 20;//final不写也行,但是外部成员变量值不能便,方便内部类使用
// final int age = 20;
public void methodMyOuter(){
class MyInter{
public void methodMyInter(){
System.out.println(age);//在局部内部类中可以访问外部类的成员方法
}
}
MyInter myinter = new MyInter();
myinter.methodMyInter();
}
}
测试类
public class Test {
public static void main(String[] args) {
MyOuter o = new MyOuter();
o.methodMyOuter();
}
}
匿名内部类【重点】
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,
那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称() {
// 覆盖重写所有抽象方法
};
对格式“new 接口名称() {...}”进行解析:
1. new代表创建对象的动作
2. 接口名称就是匿名内部类需要实现哪个接口
3. {...}这才是匿名内部类的内容
另外还要注意几点问题:
1. 匿名内部类,在【创建对象】的时候,只能使用唯一一次。
如果希望多次创建对象,而且类的内容一样的话,那么就需要使用单独定义的实现类了。
2. 匿名对象,在【调用方法】的时候,只能调用唯一一次。
如果希望同一个对象,调用多次方法,那么必须给对象起个名字。
3. 匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】
强调:匿名内部类和匿名对象不是一回事!!!
代码篇
接口
public interface MyInterface {
public void Method1();
void Method2();
}
接口实现类
public class MyInterImpl implements MyInterface{
@Override
public void Method1() {
System.out.println("覆盖重写1");
}
@Override
public void Method2() {
System.out.println("覆盖重写2");
}
}
测试类
public class DemoMain {
public static void main(String[] args) {
//匿名内部类
MyInterface obj = new MyInterface() {
@Override
public void Method1() {
System.out.println("覆盖重写Method1方法");
}
@Override
public void Method2() {
System.out.println("覆盖重写Method2方法");
}
};
obj.Method1();
obj.Method2();
System.out.println("===============");
//匿名内部类匿名对象
new MyInterface(){
@Override
public void Method1() {
System.out.println("覆盖重写1");
}
@Override
public void Method2() {
System.out.println("覆盖重写2");
}
}.Method1();
new MyInterface(){
@Override
public void Method1() {
System.out.println("覆盖重写1");
}
@Override
public void Method2() {
System.out.println("覆盖重写2");
}
}.Method2();
}
}
类作为成员变量类型
案例:创建一个英雄类,成员方法有姓名,年龄,武器。其中,武器单独是一个类。
英雄类
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 Show(){
System.out.println("我是:"+getName()+",今年"+getName()+"岁。"+"我使用:"+weapon.getCode());
}
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;
}
}
武器类
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;
}
}
测试类
public class DemoMain {
public static void main(String[] args) {
//创建一个英雄对象
Hero hero = new Hero();
hero.setName("孙悟空");
hero.setAge(550);
//创建一个武器对象
Weapon weapon = new Weapon();
weapon.setCode("金箍棒");
hero.setWeapon(weapon);
hero.Show();
}
}
接口作为成员变量类型
案例:创建一个英雄类,成员方法有:姓名,技能。其中,技能使用接口实现。
英雄类
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 showGame(){
System.out.println("姓名"+getName()+"触发技能:");
// skill.method();
skill.method();
}
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;
}
}
接口
public interface Skill {
public void method();
}
接口实现类
public class SkillImpl implements Skill{
@Override
public void method() {
System.out.println("实现接口抽象方法覆盖重载");
System.out.println("触发技能:啪啪啪");
}
}
测试类
public class DemoGame {
public static void main(String[] args) {
// //创建实现类对象
// SkillImpl skillImpl = new SkillImpl();
// //创建对象
// Hero hero = new Hero();
// hero.setSkill(skillImpl);
// hero.setName("哪吒");
// hero.showGame();
//方法二
// //创建接口匿名内部类,写入技能方法
// Skill skill = new Skill() {
// @Override
// public void method() {
// System.out.println("触发技能:当当当");
// }
// };
// //创建对象
// Hero hero = new Hero();
// hero.setName("哪吒");
// hero.setSkill(skill);
// hero.showGame();
//方法三:匿名内部类匿名对象
Hero hero = new Hero();
hero.setName("哪吒");
hero.setSkill(new Skill() {
@Override
public void method() {
System.out.println("触发技能:咚咚咚咚");
}
});
hero.showGame();
};
}
接口作为方法的参数或者返回值
import java.util.ArrayList;
import java.util.List;
/*
java.util.List正是ArrayList所实现的接口。
*/
public interface DemoInterface {
public static void main(String[] args) {
//左边是接口名称,右边是实现类名称,这就是多态的写法
List<String> list = new ArrayList<>();
List<String> li = adds(list);
for (int i = 0; i < li.size(); i++) {
System.out.println(li.get(i));
}
}
public static List<String> adds(List<String> list){
list.add("张三");
list.add("李四");
list.add("王二");
list.add("麻子");
return list;
}
}
本章节已结束,喜欢的小伙伴可以在评论区一起交流,谢谢支持!