11 final关键字、权限修饰符、内部类

final、权限、内部类

一、final关键字

1. final关键字概念与四种用法

  • final关键字代表最终、不可改变。
  • 常见的四种方法:
    • 修饰一个类
    • 修饰一个方法
    • 修饰一个局部变量
    • 修饰一个成员变量

2. final关键字用于修饰类

  • 格式:

    public final class 类名称{
      //...
    }
    
  • 含义:当前这个类是不能有任何的子类。

  • 注意:一个类如果是final的,那么其中所有的成员方法都是无法进行覆盖重写的。(因为不可被继承)

    //被final修饰,不可被继承
    public final class MyClass {
    }
    //不可继承被final修饰的类
    public class MySubClass /*extends MyClass*/ {
    }
    

3. final关键字用于修饰成员方法

  • 格式:

    public final 返回值类型 方法名称(参数列表){
      //...
    }
    
  • 含义:当final关键字用来修饰一个方法的时候,这个方法就是最终方法,即不能被覆盖重写。

  • 注意:对类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。

4. final关键字用于修饰局部变量

  • 格式:
    • final 数据类型 变量名称 = 数据值;
    • final 数据类型 变量名称; 变量名称 = 数据值;
  • 含义:一旦使用final关键字来修饰局部变量,那么这个变量就不能进行更改。
  • 注意:
    • 对于基本类型来说,是变量当中的数据值不可更改。
    • 对于引用类型来说,是变量当中的地址值不可更改。

5. final关键字用于修饰成员变量

  • 格式:

    • public final 变量类型 变量名称 = 数据值;

    • 1.public final 变量类型 变量名称;
      2.使用构造方法进行赋值。
      
  • 含义:对于成员变量来说,如果使用final关键字修饰,那么这个变量也是不可变的。

  • 注意:

    • 由于成员变量具有默认值,但是用了final之后不会再给默认值了,必须手动进行赋值。
    • 对于final的成员变量,可以通过直接赋值或者通过构造方法赋值,二者只能选其一。

二、四种权限修饰符

  • public > protected > (default) > private
publicprotected(default)private
同一个类✔️✔️✔️✔️
同一个包✔️✔️✔️
不同包子类✔️✔️
不同包非子类✔️

三、内部类

1. 内部类的概念与分类

  • 如果一个事物的内部包含另一事物,那么这就是一个类内部包含另一个类。
  • 分类:
    • 成员内部类
    • 局部内部类(包含匿名内部类)

2. 成员内部类的定义

  • 格式

    修饰符 class 外部类名称{
      修饰符 class 内部类名称{
        //...
      }
      //...
    }
    
  • 注意:

    • 内用外:随意访问。
    • 外用内:借助内部类对象。
public class Body { //外部类
    //内部类
    public class Heart{
        public void beat() {
            System.out.println("心脏跳动:怦怦怦!");
            //可以任意访问外部类的成员
            System.out.println(name);
        }
        
    }
    
    private String name;

    public Body() {
    }

    public Body(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

3. 成员内部类的使用

  • 间接方式:在外部类的方法中,使用内部类;然后main方法只是调用外部类的方法。
  • 直接方式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
public class Body { //外部类
    //内部类
    public class Heart{
        public void beat() {
            System.out.println("心脏跳动:怦怦怦!");
            //可以任意访问外部类的成员
            System.out.println("我在" + name + "的身体里!");
        }
    }

    private String name;

    public Body() {
    }

    public Body(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public void bodyMethod(){
        Heart heart = new Heart();
        System.out.println("身体方法!");
        heart.beat();
    }
}

public class UseBody {
    public static void main(String[] args) {
        //间接方式
        Body body = new Body();
        body.bodyMethod();  //身体方法!
                            //心脏跳动:怦怦怦!
                            //我在null的身体里!

        //直接方式
        Body.Heart heart = new Body().new Heart();
        heart.beat();  //心脏跳动:怦怦怦!
                       //我在null的身体里!
    }
}

4. 内部类的同名变量访问

  • 如果出现了重名现象,那么格式是:外部类名称.this.外部类成员变量名;
public class Outer { // 外部类
    int num = 10; // 外部类成员变量
    public class Inner{ // 内部类
        int num = 20; // 内部类成员变量
        public void methodInner() {
            int num = 30; // 局部变量
            System.out.println(num); // 局部变量 30
            System.out.println(this.num); // 内部类成员变量 20
            System.out.println(Outer.this.num); // 外部类成员变量 10
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().new Inner();
        inner.methodInner();  // 30 20 10
    }
}

5. 局部内部类定义

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

  • “局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

  • 定义格式:

    修饰符 class 外部类名称 {
      修饰符 返回值类型 外部类方法名称(参数列表){
        class 局部内部类名称{
          //...
        }
      }
    }
    
  • 使用

    public class Outer {
        public void methodOuter(){
            class Inner{
                int num = 10;
                public void methodInner(){
                    System.out.println(num);
                }
            }
            Inner inner = new Inner();
            inner.methodInner();
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Outer outer = new Outer();
            outer.methodOuter();  // 10
        }
    }
    

6. 局部内部类的final问题

  • 局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的
  • 注:从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。
  • 原因:
    • new出来的对象是在堆内存当中的。
    • 局部变量是跟着方法走的,在内存当中。
    • 方法运行结束之后,立刻出栈,局部变量就会消失。
    • 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。

7. 匿名内部类

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

  • 匿名内部类的定义格式:

    接口名称 对象名 = new 接口名称() {
      // 覆盖重写所有的抽象方法。
    };
    
  • 使用:

    public interface MyInterface {
        public abstract void method();
    }
    public class Test {
        public static void main(String[] args) {
            MyInterface myInterface = new MyInterface() {
                @Override
                public void method() {
                    System.out.println("匿名内部类实现了方法!");
                }
            };
            myInterface.method(); // 匿名内部类实现了方法!
        }
    }
    

8. 匿名内部类的注意事项

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

    • new代表创建对象的动作。
    • 接口名称就是匿名内部类需要实现哪个接口。
    • {...}是匿名内部类的内容。
  • 注意:

    • 匿名内部类,在创建对象的时候,只能使用唯一一次。如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了。
    • 匿名对象,在调用方法的时候,只能调用唯一一次。如果希望同一个对象,调用多次方法,那么就必须给对象起个名字。
    • 匿名内部类是省略了实现类/子类名称,但是匿名对象是省略了对象名称匿名内部类与匿名对象不是一个东西。

四、类作为成员变量类型

public class Hero {
    private String name;
    private int age;
    private Weapen weapen;

    public Hero() {
    }

    public Hero(String name, int age, Weapen weapen) {
        this.name = name;
        this.age = age;
        this.weapen = weapen;
    }

    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 Weapen getWeapen() {
        return weapen;
    }

    public void setWeapen(Weapen weapen) {
        this.weapen = weapen;
    }

    public void attack(){
        System.out.println("年龄为" + age + "岁的" + name
                + "用" + weapen.getWeapenName() + "攻击了你!");
    }
}

public class Weapen {
    private String weapenName;

    public Weapen() {
    }

    public Weapen(String weapenName) {
        this.weapenName = weapenName;
    }

    public String getWeapenName() {
        return weapenName;
    }

    public void setWeapenName(String weapenName) {
        this.weapenName = weapenName;
    }
}

public class Test {
    public static void main(String[] args) {
        Weapen weapen = new Weapen("棒棒糖");
        Hero hero = new Hero("猪猪侠",5,weapen);
        hero.attack(); // 年龄为5岁的猪猪侠用棒棒糖攻击了你!
    }
}

五、接口作为成员变量类型

public class Hero {
    private String name;
    //接口作为成员变量类型
    private Skill skill;

    public void attacke() {
        System.out.print(name);
        skill.use();
    }

    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;
    }
}

public interface Skill {
    public  void  use();
}

public class SkillImpl implements Skill{
    @Override
    public void use() {
        System.out.println("使用了技能!");
    }
}

public class Test {
    public static void main(String[] args) {
        Hero hero = new Hero();
        hero.setName("猪猪侠");
        //1.使用实现类作为参数
        //hero.setSkill(new SkillImpl());
        //hero.attack();
        //2.使用匿名内部类
       /* Skill skill = new Skill(){
            @Override
            public void use() {
                System.out.println("使用了技能!");
            }
        };
        hero.setSkill(skill);
        hero.attacke();*/
        //3.同时使用匿名内部类和匿名对象
        hero.setSkill(new Skill() {
            @Override
            public void use() {
                System.out.println("使用了技能!");
            }
        });
        hero.attacke();
    }
}

六、接口作为方法的参数或返回值

import java.util.ArrayList;
import java.util.List;

//import java.util.List是ArrayList所实现的接口
public class Test {
    public static void main(String[] args) {
        //左边是接口名称,右边是实现类名称,这就是多态写法
        List<String> list = new ArrayList<>();
        List<String> result = addName(list);
        for (int i = 0; i < result.size(); i++) {
            System.out.println(result.get(i));
        }
    }

    public static List<String> addName(List<String> list) {
        list.add("朱古力");
        list.add("猪猪侠");
        return list;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值