目录
一、final关键字
1.1 概述
学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承API中提供的类,改写其内容呢? 显然这是不合适的。为了避免这种随意改写的情况。
Java提供了 final 关键字用于修饰不可改变内容。
final: 不可改变。可以用于修饰类、方法和变量。
类:被修饰的类,不能被继承。
方法:被修饰的方法,不能被重写。
变量:被修饰的变量,不能被重新赋值。
1.2使用方式
修饰类
格式如下:
final class 类名{
}
代码:
final class Fu {
}
// class Zi extends Fu {} // 报错,不能继承final的类
1.3 修饰方法
格式如下:
修饰符 final 返回值类型 方法名(参数列表){
//方法体
}
public class Test01 {
public static void main(String[] args) {
final int a = 5;//final修饰变量,变量一旦赋值后不允许修改它的值(常量)
}
}
1.4 修饰变量-局部变量
1.局部变量——基本类型 基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:
public static void main(String[] args) {
// 声明变量,使用final修饰
final int a;
// 第一次赋值
a = 10;
// 第二次赋值
a = 20; // 报错,不可重新赋值
// 声明变量,直接赋值,使用final修饰
final int b = 10;
// 第二次赋值
b = 20; // 报错,不可重新赋值
}
1.5 修饰变量-成员变量
成员变量涉及到初始化的问题,初始化方式有显示初始化和构造方法初始化,只能选择其中一个:
-
显示初始化(在定义成员变量的时候立马赋值)(常用);
-
public class Student {
final int num = 10;
} -
构造方法初始化(在构造方法中赋值一次)(不常用,了解即可)。
注意:每个构造方法中都要赋值一次
public class Student {
final int num = 10;
final int num2;
public Student() {
this.num2 = 20;
// this.num2 = 20;
}
public Student(String name) {
this.num2 = 20;
// this.num2 = 20;
}
}
被final修饰的常量名称,一般都有书写规范,所有字母都大写。
二、访问修饰符
2.1 概述
在lava中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限。
public: 公共的 所修饰的类、变量、方法,在内外包均具有访问权限;
protected: 受保护的 这种权限是为继承而设计的,protected所修饰的成员,对所有子类是可访问的,单只对同包的类是可访问的,对外包的非子类是不可以访问;
default: 默认的 只对同包的类具有访问的权限,外包的所有类都不能访问;
private:私有的 私有的权限,只对本类的方法可以使用;
2.2 不同权限的访问能力
可见,public具有最大权限。private则是最小权限。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
成员变量使用 private ,隐藏细节。
构造方法使用 public,方便创建对象。
成员方法使用 public,方便调用方法。
小贴士: 不加权限修饰符,其访问能力与default修饰符相同
//同一类中都可以访问
public class Person {
public String name;
protected int age;
String sex;
private String addr;
public void fun(){
name="zy";
age=19;
sex="女";
addr="光山";
}
}
//同一包中 子类
public class Student extends Person{
public void fun(){
this.name="zs";
this.age=18;
this.sex="男";
}
}
//同一包中 无关类
public class Test01 {
public static void main(String[] args) {
Person p = new Person();
p.name="zy";
p.age=20;
p.sex="女";
}
}
//不同包的子类
public class Teacher extends Person {
public void fun(){
this.name="za";
this.age=20;
}
}
//不同包中的无关类
public class Test01 {
public static void main(String[] args) {
Person p = new Person();
p.name="dxx";
}
}
三、内部类
3.1 概述
什么是内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
成员内部类
成员内部类:定义在类中方法外的类。
定义格式:
class 外部类{
class 内部类{}
}
访问特点
内部类可以直接访问外部类的成员,包括私有成员。
外部类要访问内部类的成员,必须要建立内部类的对象。
创建内部类对象格式:
外部类名.内部类名 对象名 new 外部类型().new 内部类型();
3.2 匿名内部类[重点]
匿名内部类:是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作
1.定义子类
2.重写接口中的方法
3.创建子类对象
4.调用重写后的方法
我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢? 匿名内部类就是做这样的快捷方式。
前提
匿名内部类必须继承一个父类或者实现一个父接口 。
格式
new 父类名或者接口名(){
//方法重写
@Override
public void method() {
// 执行语句
}
}
使用方式
public abstract class Person {
public void say(){
System.out.println("学生在读书");
}
}
public class Student extends Person{
public void say(){
System.out.println("学生在读书");
}
}
public abstract interface USB {
public abstract void read();
}
public class Kingston implements USB{
@Override
public void read() {
System.out.println("金士顿完成读操作");
}
}
public class Test01 {
public static void main(String[] args) {
Person p = new Student();//实例化Person的子类Student对象
//匿名内部类: 它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象;
//如果抽象类或者接口的抽象方法没办法具体定义实现,或者需要根据具体情况具体实现,此时没办法定义子类,可以使用匿名类
Person person = new Person() {
@Override
public void say() {
System.out.println("匿名内部类实现抽象方法say");
}
};
//匿名内部类:直接创建子类对象 重写方法 然后调用
USB usb = new USB() {
@Override
public void read() {
System.out.println("金士顿读操作");
}
};
usb.read();
//定义子类 实现方法 创建子类对象 调用方法
USB usb1 = new Kingston();
usb1.read();
}
}
public class User {
public static void main(String[] args) {
/**
* 基本数据类型和引用类型作为参数的区别:
* 1.基本数据类型作为参数,修改的是剧本,不会更改本身;
* 2.引用数据类型作为参数,修改的是本身;
*/
int a = 10;
System.out.println("改变前a的值:" + a); //10
change(a);
System.out.println("改变后a的值:" + a); //10
System.out.println("-------------------------");
int[] arr=new int[3];
arr[0]=10;
System.out.println("改变前arr数组第一个元素的值:" + arr[0]);//10
change(arr);
System.out.println("改变后arr数组第一个元素的值:" + arr[0]);//50
}
public static void change(int a){
a=50;
}
public static void change(int[] arr){
arr[0]=50;
}
}