权限修饰符和内部类

Posted lf-637

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了权限修饰符和内部类相关的知识,希望对你有一定的参考价值。

一、final关键字

final关键字代表最终、不可改变的。学习了继承后,我们知道子类可以在父类的基础上改写父类内容,比如方法重写。为了避免随意改写的情况发生,Java提供了 final 关键字,用于修饰不可改变内容 。主要表现在使用final关键字后:

  • 类:被修饰的类,不能被继承
  • 方法:被修饰的方法,不能被重写
  • 变量:被修饰的变量,不能被重新赋值

1. 常见四种用法

  • 可以修饰一个类
  • 可以修饰一个方法
  • 可以修饰一个局部变量
  • 可以修饰一个成员变量

① 修饰类

格式:

public final class 类名称{
	//....
}

含义:当前这个类不能有任何子类(可以理解为太监类)。所以也无法对成员方法进行覆盖重写

② 修饰方法

格式如下:

修饰符 final 返回值类型 方法名(参数列表){
	//方法体
}

含义:用final修饰的方法可以被继承,但是不能被子类的重写

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

③ 修饰变量

  • 修饰局部变量

    • 一旦使用final变量修饰局部变量,则此变量就不能进行更改

    • 基本类型来说,不可变指的是变量中的数据不可改变

      • public class FinalDemo1 {
        	public static void main(String[] args) {
        		// 声明变量,使用final修饰
        		final int a;
        		// 第一次赋值
        		a = 10;
        		// 第二次赋值
        		a = 20; // 报错,不可重新赋值
        		
        		// 声明变量,直接赋值,使用final修饰
        		final int b = 10;
        		// 第二次赋值
        		b = 20; // 报错,不可重新赋值
        	}
        }
        
    • 引用类型来说,不可变指的是变量中的地址值不可改变

      • public class FinalDemo2 {
        	public static void main(String[] args) {
        		// 创建 User 对象
        		final User u = new User();
        		// 创建 另一个 User对象
        		u = new User(); // 报错,指向了新的对象,地址值改变。
        		
        		// 调用setName方法
        		u.setName("张三"); // 可以修改
        	}
        }
        
  • 修饰成员变量

    • 对于成员变量来说,如果使用final关键字进行修饰,那么这个变量也是不可变
    • 由于成员变量具有默认值,使用了final之后没有默认值,必须手动赋值
      • 对于final的成员变量,要么直接赋值,要么通过构造方法赋值
      • 通过构造方法赋值,必须保证类中所有重载的构造方法都最终会对final中的成员变量进行赋值

二、权限修饰符

Java中提供了四种访问权限符,访问权限大小:public > protected > (default) > private

不同权限的服务能力:

public protected default(空的) private
同一类中
同一包中(子类和无关类)
不同包的子类
不同包中的无关类

可见,public具有最大权限。private则是最小权限 。编写代码时,如果没有特殊的考虑,建议这样使用权限

  • 成员变量使用 private ,隐藏细节
  • 构造方法使用 public ,方便创建对象
  • 成员方法使用 public ,方便调用方法

注:不加权限修饰符,其访问能力与default修饰符相同


三、内部类

很多时候我们创建类的对象的时候并不需要使用很多次,每次只使用一次,这个时候我们就可以使用内部类

1. 概述

内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了

内部类不是在一个java源文件中编写俩个平行的俩个类,而是在一个类的内部再定义另外一个类。 我们可以把外边的类称为外部类,在其内部编写的类称为内部类

2. 分类

内部类分为四种 :

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

① 成员内部类

  • 成员内部类 :定义在类中方法外的类

  • 定义格式:

    • class 外部类 {
      	class 内部类{
      	}
      }
      
    • 在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机类 Engine ,这时, Engine 就可以使用内部类来描述,定义在成员位置

    • class Car { //外部类
      	class Engine { //内部类
      	}
      }
      
  • 访问特点

    • 内用外,随意访问。即内部类可以直接访问外部类的成员,包括私有成员
    • 外部类要访问内部类的成员,必须要建立内部类的对象
  • 使用成员内部类

    • 间接方式:通过外部类的对象调用外部类的方法,在里面间接使用内部类
    • 直接方式:记住格式
      • 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
  • 内部类的重名变量访问

    • 格式:外部类名称.this.外部类成员变量名

② 静态内部类

使用static修饰的内部类就叫静态内部类 。下面复习static的用法:

(1). 一般只修饰变量和方法,平常不可以修饰类,但是内部类却可以被static修饰

(2). static修饰成员变量:整个类的实例共享静态变量

(3). static修饰方法:静态方法,只能够访问用static修饰的属性或方法,而非静态方法可以访问static修饰的方法或属性

(4). 被static修饰了的成员变量和方法能直接被类名调用

(5). static不能修饰局部变量,平常就用来修饰成员变量和方法

注意:

  • 静态内部类能够直接被外部类给实例化,不需要使用外部类对象
    • Outer.Inner inner = new Outer.Inner();
  • 静态内部类中可以声明静态方法和静态变量,但是非静态内部类中就不可以声明静态方法和静态变量

③ 局部内部类

局部内部类是在一个方法内部声明的一个类,可以访问外部类的成员变量及方法。如果局部内部类中要访问该内部类所在方法中的局部变量,那么这个局部变量就**必须是有效final修饰的 **

public class Outer {
	private int id;
	//在method01方法中有一个Inner内部类,这个内部类就称为局部内部类
	public void method01(){class Inner{
		public void in(){
			System.out.println("这是局部内部类");
		}
	}
}
}

局部内部类一般的作用跟在成员内部类中总结的差不多 ,但有两点要注意

  • 在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰

    • new出来的对象在堆内存中,而局部变量在栈内存中,是跟着方法走的。若方法运行结束将立即出栈,此时局部变量会跟着消失。这个时候局部内部类对象在想去调用该局部变量,就会报错,因为该局部变量已经没了

    • 当局部变量用fanal修饰后,就会将其加入常量池中,即使方
      法出栈了,该局部变量还在常量池中,局部内部类也能够调用。所以局部内部类想要调用局部变量时,需要使用final修饰。

    • public void methodOuter(){
          final int num = 10;
      }
      	class myInner(){
              public void methoeInner(){
                  System.out.println(num);
              }
          }
      
  • 局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法

④ 匿名内部类【重点】

如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,此时可以省略该类的定义,改为使用匿名内部类

  • 概述

    • 匿名内部类是最常用的一种内部类 ,是内部类的简化写法。
    • 它的本质是一个带具体实现的父类或者父接口的匿名的子类对象
    • 如当使用一个接口时,需要做包括定义重写在内的好几步操作 。而使用匿名内部类就能简化成一步
  • 前提

    • 匿名内部类必须继承一个父类或者实现一个父接口
  • 格式

    • new 父类名或接口名(){
      	//覆盖重写所有抽象方法
      
      };
      
      • new 代表创建对象的动作
      • 接口名称就是你们内部类需要实现哪个接口
      • 大括号内的是匿名内部类
  • 注意的问题

    • 匿名内部类在创建对象的时候,只能使用唯一一次。如果希望多次创建对象,那就使用单独打印的实现类
    • 匿名对象在调用方法的时候,只能使用唯一一次。如果希望多同一对象调用多次方法,那就必须给对象起个名字
    • 匿名内部类是省略了实现类/子类,但是匿名对象是省略了对象名称。注意,两者不同。

以上是关于权限修饰符和内部类的主要内容,如果未能解决你的问题,请参考以下文章

访问修饰符和继承

private/默认/protected/public权限修饰符的区别

修饰符和多态

php面向对象-修饰符和抽象类和接口

修饰符和关键字和继承

Java修饰符和String