每日一知识点 - Java常用关键字

😀 准备好了吗?让我们一起步入这座Java神奇的城堡,解开每一个关键字的奥秘,成为真正的Java魔法师!

📝 Java常用关键字

访问权限修饰符

在Java 中,提供了四种访问权限控制:默认访问权限(包访问权限)、public、private、protected

default  //默认,啥都不写。同一包内可见,不同包的子类不可见,未使用任何修饰符的都默认,使用对象:类,接口,变量,方法。
public  //公共的,所有类可见,使用对象:类,接口,变量,方法。
protected //受保护的 对同一包内的类和所有子类(不同包子类)可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
private //私有的    在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

public > protected > default > private
访问范围privatedefaultprotectedpublic
同一个类可以访问可以访问可以访问可以访问
同一个包中的其他类不可访问可以访问可以访问可以访问
不同包中的子类不可访问不可访问可以访问可以访问
不同包中的非子类不可访问不可访问不可访问可以访问

默认访问修饰符

使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public

特征:

  • 也称为包级私有(package-private)

  • 可以被同一个包内的任何类访问

  • 不能被其他包的类访问

  • 适用于只在包内使用的类、方法或变量

class test{
}

public 关键字

当一个类被声明为 public 时,它就具有了被其他包中的所有类访问的可能性,只要包中的其他类在程序中使用 import 语句引入该类,就可以访问和引用这个类。

特征:

  • 最宽松的访问级别

  • 可以被任何类访问

  • 用于定义类的公共接口

public class Test{
    public static void main(String[] arguments) {
          // ...
    }
}

private 关键字

private 修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用,具有最高的保护级别。

特征:

  • 最严格的访问级别

  • 只能在声明它的类内部访问

  • 用于隐藏类的实现细节

  • 常用于封装,确保类的内部状态只能通过类的方法来修改

public class Logger {
   private String format;
   public String getFormat() {
      return this.format;
   }
}

format 变量为私有变量,所以其他类不能直接得到该变量的值,
为了能够是其他类能够操作该变量,定义了public方法,getFormat(),来返回format 的值。

protected 关键字

用 protected 关键字修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类。

protected 可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)接口及接口的成员变量和成员方法不能声明为 protected。

特征:

  • 可以被同一个包内的任何类访问

  • 可以被不同包中的子类访问

  • 常用于允许子类访问父类的某些细节,同时对外部类隐藏这些细节

class AudioPlayer {
   protected boolean openSpeaker(Speaker sp) {
      // 实现细节
   }
}
 
class StreamingAudioPlayer extends AudioPlayer {
   protected boolean openSpeaker(Speaker sp) {
      // 实现细节
   }
}

子类重写父类的方法。

注意点:

  • 类的访问控制符只能是默认访问权限或者public修饰,但是变量和方法则都可以修饰。

    public class Test{}
    
    class Test{}
    
  • 父类中声明为 public 的方法在子类中也必须为 public。

  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。

  • 父类中声明为 private 的方法,不能够被子类继承。

  • 对于一个 Java 源代码文件,如果存在 public 类的话,只能有一个 public 类,且此时源代码文件的名称必须和 public 类的名称完全相同。

    如果还存在其他类,这些类在包外是不可见的。如果源代码文件没有 public 类,则源代码文件的名称可以随意命名。

简单记忆:不想让别人看的就 private,想让人看的就 public,想同一个班级/部门看的就默认,想让下一级看的就 protected


其他常用关键字

this 关键字

this 关键字在Java中用于引用当前对象,避免变量名冲突,调用类中的其他方法或构造器,以及实现方法链调用。

1、引用当前对象

在一个对象的方法或构造器中,this 指向调用该方法或构造器的对象。这样可以访问该对象的实例变量和其他方法。

如果构造方法中没有使用 this 关键字,name 指向的并不是实例变量而是参数本身。

使用了this 关键字后,this.xxx 指向的就是实例变量,而不再是参数本身了。

当然如果参数名和实例变量名不相同的话,就不必使用this 关键字了 。

public class Dog {
    private String name;

    public Dog(String name) {
        this.name = name;  // 使用 this 区分参数 name 和实例变量 name
    }

    public void setName(String name) {
        this.name = name;  // 使用 this 区分参数 name 和实例变量 name
    }

    public String getName() {
        return this.name;  // 使用 this 指向当前对象的实例变量 name
    }
}

2、调用当前对象的方法

在一个方法中,可以使用 this 关键字调用同一个类中的其他方法。如果没有使用的话,编译器会自动帮我们加上。

public class Dog {
    private String name;

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

    public void bark() {
        System.out.println("Woof!");
    }

    public void callBark() {
        this.bark();  // 调用当前对象的 bark 方法
    }

    public void callBark2() {
        bark();  // 编译器会自动加上this关键字
    }
}

3、调用当前对象的构造器

在一个构造器中,可以使用 this 调用同一个类中的另一个构造器。这通常用于构造器的重载,以避免代码重复。

💡
需要注意的是, this() 必须放在构造方法的第一行,否则就报错了!
public class Dog {
    private String name;
    private int age;

    public Dog(String name) {
        this(name, 0);  // 调用带有两个参数的构造器
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

4、作为参数在方法中传递

this 关键字可以作为参数在方法中传递,它指向的是当前类的对象。

public class Param {
    void method1(Param p) {
        System.out.println(p);
    }

    void method2() {
        method1(this);
    }

    public static void main(String[] args) {
        Param p = new Param();
        System.out.println(p);
        p.method2();
    }
}
/**
Param@77459877
Param@77459877
**/

5、在构造函数中传递this

在某些情况下,可以在构造函数中将当前对象传递给其他类的构造函数或方法。

public class MyClass {
    private String name;

    public MyClass(String name) {
        this.name = name;
        Helper helper = new Helper(this);//this 指向的是new MyClass()这个对象
        helper.printDetails();
    }

    public String getName() {
        return name;
    }
}

class Helper {
    private MyClass myClass;

    public Helper(MyClass myClass) {
        this.myClass = myClass;
    }

    public void printDetails() {
        System.out.println("Name: " + myClass.getName());
    }
}

public class Main {
    public static void main(String[] args) {
        new MyClass("Alice"); // 输出: Name: Alice
    }
}

6、返回当前对象

在某些设计模式中,特别是方法链(method chaining)中,this 可以用于返回当前对象,从而可以连续调用该对象的方法。

this 关键字作为方法的返回值的时候,方法的返回类型为类的类型。

public class Dog {
    private String name;

    public Dog setName(String name) {
        this.name = name;
        return this;  // 返回当前对象 dog
    }

    public Dog printName() {
        System.out.println(this.name);
        return this;  // 返回当前对象
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("Buddy").printName();  // 连续调用方法,链式调用
    }
}

super 关键字

super关键字主要用于引用父类的成员(变量、方法)和构造函数。它常用于实现继承和方法重写时访问父类的成员。

1. 访问父类的实例变量

当子类和父类中有同名的实例变量时,可以使用super关键字来访问父类的实例变量。

class Parent {
    int x = 10;
}

class Child extends Parent {
    int x = 20;

    void display() {
        System.out.println("Child x: " + x); // 子类的 x
        System.out.println("Parent x: " + super.x); // 父类的 x
    }

    public static void main(String[] args) {
        new Child().display();
    }
}
/**
Child x: 20
Parent x: 10
**/

2. 调用父类的方法

当子类重写了父类的方法时,可以使用super关键字调用父类的版本。

class Parent {
    void display() {
        System.out.println("Parent display()");
    }
}

class Child extends Parent {
    void display() {
        super.display(); // 调用父类的 display() 方法
        System.out.println("Child display()");
    }

    public static void main(String[] args) {
        new Child().display();
    }
}
/**
Parent display()
Child display()
**/

3. 调用父类的构造函数

在子类的构造函数中,可以使用super关键字来调用父类的构造函数。必须在子类构造函数的第一行使用super

class Parent {
    Parent() {
        System.out.println("Parent Constructor");
    }

    Parent(String message) {
        System.out.println("Parent Constructor: " + message);
    }
}

class Child extends Parent {
    Child() {
        super("Hello from Child"); // 调用父类的带参数构造函数
        System.out.println("Child Constructor");
    }

    public static void main(String[] args) {
        Child obj = new Child();
    }
}
/**
Parent Constructor: Hello from Child
Child Constructor
**/

static 关键字

static关键字用于声明类成员(字段和方法)为类级别的,而不是实例级别的。这意味着static成员属于类本身,而不是类的实例(对象)。

1. static变量(静态变量)

静态变量,也称为类变量,是类所有实例共享的变量。它们在内存中只有一个副本,无论创建了多少个类的实例,都使用同一个静态变量。

  • 存储位置static变量存储在方法区(Method Area),该区域是所有实例共享的区域。

  • 生命周期static变量在类加载时初始化,并在类卸载时销毁,生命周期贯穿整个应用程序的运行过程。

public class MyClass {
    static int staticVar = 0; // 静态变量

    public MyClass() {
        staticVar++; // 每次创建实例时,staticVar递增1
    }

    public void display() {
        System.out.println("staticVar: " + staticVar); // 打印当前的staticVar值
    }

    public static void main(String[] args) {
        MyClass obj1 = new MyClass();
        obj1.display(); // 输出: staticVar: 1

        MyClass obj2 = new MyClass();
        obj2.display(); // 输出: staticVar: 2

        MyClass obj3 = new MyClass();
        obj3.display(); // 输出: staticVar: 3
    }
}
//所以输出是 1,2,3,因为同一个变量的地址没变。
如果类中 int staticVar = 0;为实例变量,那么输出就为1,1,1
存储位置:实例变量存储在堆内存中,每个实例都有自己独立的变量副本。 生命周期:实例变量的生命周期与实例的生命周期相同,当实例被垃圾回收时,实例变量也被回收。每次创建新实例时,实例变量都会重新初始化为0,而不是继续使用同一个 static变量。

2.static方法(静态方法)

  • 静态方法是属于类的,而不是属于实例的。

  • 它们可以在不创建类的实例的情况下调用。

  • 静态方法只能访问静态变量和其他静态方法,不能访问实例变量或调用非静态方法。

java.lang.Math 类的几乎所有方法都是静态的,可以直接通过类名来调用,不需要创建类的对象。

public class MyClass {
    static int staticVar = 0;

    static void staticMethod() {
        System.out.println("Static method called.");
        System.out.println("staticVar: " + staticVar);
    }

    public static void main(String[] args) {
        MyClass.staticMethod(); // 调用静态方法
    }
}
main方法为静态方法
如果 main 方法不是静态的,就意味着 Java 虚拟机在执行的时候需要先创建一个对象才能调用 main 方法,而 main 方法作为程序的入口,创建一个额外的对象显得非常多余。

3.static块(静态代码块)

静态代码块用于初始化类的静态变量。它在类加载时执行一次,可以包含多个静态代码块,按它们在类中出现的顺序执行。

public class StaticBlock {
    static {
        System.out.println("静态代码块");
    }

    public static void main(String[] args) {
        System.out.println("main 方法");
    }
}
/**
静态代码块
main 方法
**/

4.static内部类(静态内部类)

静态内部类可以独立于外部类的实例存在。静态内部类不能访问外部类的实例变量和方法,但可以访问外部类的静态变量和方法。

public class OuterClass {
    static int staticVar = 10;

    static class InnerClass {
        void display() {
            System.out.println("Static variable from OuterClass: " + staticVar);
        }
    }

    public static void main(String[] args) {
        OuterClass.InnerClass inner = new OuterClass.InnerClass();
        inner.display();
    }
}

5.static导入(静态导入)

静态导入允许直接使用静态成员(方法或变量),而无需通过类名限定。在导入某些常用的静态成员时非常方便,如Math类的方法。

import static java.lang.Math.*;

public class MyClass {
    public static void main(String[] args) {
        double result = sqrt(16); // 直接使用 Math.sqrt() 方法
        System.out.println("Square root of 16 is: " + result);
    }
}

final 关键字

final关键字在Java中是一个非常重要的修饰符,可以用来修饰类、方法和变量。

1、final 变量

final 修饰的变量即成为常量,只能赋值一次。换句话说,被 final 修饰的变量无法重新赋值。

注意:final 修饰的变量不能被赋值这种说法是错误的,严格的说法是,final 修饰的变量不可被改变,一旦获得了初始值,该 final 变量的值就不能被重新赋值。

  1. final 修饰的局部变量必须使用之前被赋值一次才能使用。

  2. final 修饰的成员变量在声明时没有赋值的叫“空白 final 变量”。空白 final 变量必须在构造方法或静态代码块中初始化。、

final 和 static 一起修饰的成员变量叫做常量,常量名必须全部大写。如果一个程序中的变量使用 public static final 声明,则此变量将称为全局变量.

public class FinalDemo {
    void doSomething() {

        //局部变量
        // 没有在声明的同时赋值
        final int e;
        // 只能赋值一次
        e = 100;
        System.out.print(e);
        // 声明的同时赋值
        final int f = 200;
    }

    // 实例常量
    final int a = 5; // 直接赋值
    final int b; // 空白final变量
    // 静态常量
    final static int c = 12;// 直接赋值
    final static int d; // 空白final变量
    // 静态代码块
    static {
        // 初始化静态变量
        d = 32;
    }

    // 构造方法
    FinalDemo() {
        // 初始化实例变量
        b = 3;
        // 第二次赋值,会发生编译错误
        // b = 4;
    }

final 修饰基本类型变量和引用类型变量的区别

  • 当使用 final 修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。

  • 但对于引用类型变量而言,它保存的仅仅是一个引用,final 只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。

import java.util.Arrays;

class Person {
    private int age;

    public Person() {
    }

    // 有参数的构造器
    public Person(int age) {
        this.age = age;
    }
    // 省略age的setter和getter方法
    // age 的 setter 和 getter 方法
}

public class FinalReferenceTest {
    public static void main(String[] args) {
        // final修饰数组变量,iArr是一个引用变量
        final int[] iArr = { 5, 6, 12, 9 };
        System.out.println(Arrays.toString(iArr));
        // 对数组元素进行排序,合法
        Arrays.sort(iArr);
        System.out.println(Arrays.toString(iArr));
        // 对数组元素赋值,合法
        iArr[2] = -8;
        System.out.println(Arrays.toString(iArr));
        // 下面语句对iArr重新赋值,非法
        // iArr = null;
        // final修饰Person变量,p是一个引用变量
        final Person p = new Person(45);
        // 改变Person对象的age实例变量,合法
        p.setAge(23);
        System.out.println(p.getAge());
        // 下面语句对P重新赋值,非法
        // p = null;
    }
}

在这里插入图片描述

2、final方法

在声明类中,final 方法只被实现一次。

不能被重写:声明为final的方法不能在子类中被重写。这确保了方法的行为在继承层次结构中保持不变。

public class FinalMethodTest {

    public final void test() {
    }
}

class Sub extends FinalMethodTest {

    // 下面方法定义将出现编译错误,不能重写final方法
    public void test() {
    }
}

但是,final修饰的方法可以被重载。

public class FinalOverload {
    // final 修饰的方法只是不能被重写,完全可以被重载
    public final void test(){}
    public final void test(String arg){}
}

注意点:

对于一个 private 方法,因为它仅在当前类中可见,其子类无法访问该方法,所以子类无法重写该方法——如果子类中定义一个与父类 private 方法有相同方法名、相同形参列表、相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法。因此,即使使用 final 修饰一个 private 访问权限的方法,依然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值类型的方法。

public class PrivateFinalMethodTest {
    private final void test() {
    }
}

class Sub extends PrivateFinalMethodTest {
    // 下面的方法定义不会出现问题
    public void test() {
    }
}

这样的写法相当于子类重新定义了一个新方法,并不是重写父类的方法。

3、final

**final 修饰的类不可被继承。**当某个类被final修饰时,意味着此类无后代,不需要进行修改或扩展。

final class SuperClass {
}
class SubClass extends SuperClass {    //编译错误
}

4.、final参数

不可修改final参数在方法内部不能被修改。这可以防止方法中的参数被意外改变。

public class MyClass {
    void display(final int param) {
        System.out.println("Parameter: " + param);

        // 以下代码会导致编译错误,因为 final 参数不能被修改
        // param = 10;
    }

    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.display(5);
    }
}

instanceof 关键字

instanceof 关键字用于测试一个对象是否是一个特定类的实例,或者是这个类的子类的实例。它返回一个布尔值,表示测试结果。instanceof 通常用于类型检查,以确保安全地进行类型转换和操作。

(object) instanceof (type)

//基础使用
class Animal {}
class Dog extends Animal {}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        Dog myDog = new Dog();

        System.out.println(myAnimal instanceof Animal); // 输出: true
        System.out.println(myDog instanceof Dog); // 输出: true
        System.out.println(myDog instanceof Animal); // 输出: true
        System.out.println(myAnimal instanceof Dog); // 输出: false
    }
}

检查接口实现

instanceof也可以用于检查对象是否实现了某个接口。

interface Pet {}
class Dog implements Pet {}
class Cat {}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        Cat myCat = new Cat();

        System.out.println(myDog instanceof Pet); // 输出: true
        System.out.println(myCat instanceof Pet); // 输出: false
    }
}

null 值检查

instanceofnull值进行检查时,总是返回false。只有对象才会有 null 值,但是又因为所有的对象都可以为 null,所以也不好确定 null 到底属于哪一个类。

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = null;
        System.out.println(myAnimal instanceof Animal); // 输出: false
    }
}

使用示例:

// 先判断类型
if (obj instanceof String) {
    // 然后强制转换
    String s = (String) obj;
    // 然后才能使用
}

//或者这种
if (obj instanceof String s) {
    // 如果类型匹配 直接使用 s
}


//示例
class Animal {}
class Dog extends Animal {
    void bark() {
        System.out.println("Woof!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog(); // 多态

        if (myAnimal instanceof Dog) {
            Dog myDog = (Dog) myAnimal; // 安全转换
            myDog.bark(); // 输出: Woof!
        } else {
            System.out.println("The object is not an instance of Dog.");
        }
    }
}

📎 参考文章

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天马行空的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值