Featured image of post Java 基础笔记

Java 基础笔记

没有引言,单纯做笔记。


运算符

逻辑运算符

  • && 二方都为true,则为true;
  • || 一方为true,则为true;

位运算符

  • & 一方为0/false,则为0/false
  • | 一方为1/true,则为1/true

String

String 在实例化完成后不可变,自带final修饰符。

字符串池

在JVM中有一块内存区域,专门用于存储字符串,即字符串池(String Pool)

字面量和引用

String xxx = new String("...")String xxx = "..." 不同。

  • String xxx = new String("...") 直接在JVM的堆(Heap)创建全新的对象
  • String xxx = "..." 先检查池中有无相同字符串,有则获取相同引用

equals(Object)

  • equals(Object)方法检查字符串内容

  • ==检查字符串引用

若是用==,则两个字符串有可能指向同或不同引用,导致与预期结果不一致。

String a = "相同内容";
String b = new String("相同内容");

System.out.println(a == b); 
System.out.println( a.equals(b) )

第一个为false,引用不同;

第二个为true,引用不同,但内容相同

intern()

intern() 复制一个字符串,保持在池中引用相同。

String a = new String("Hello"); // 堆中
String b = a.intern()
String c = "Hello"; // 池中

System.out.println(a==b); // false
System.out.println(c==b); // true

对象地址

一些对象的地址一般以 A@bbbbbbbb 形式打印出来

  • A 是类的名称
  • b 是对象的哈希值

方法传参的方式

  • 基本数据类型:按值
  • 引用数据类型:按引用

静态代码块

写法如下

class A {
    static {
        // 静态代码块
    }
}

随着类的加载而运行,且只运行一次。

内部类

成员内部类

JDK 16 之前不能在成员内部类内定义静态字段。

class Outer {
    // 其他代码
    class Inner {
        // 内部类
    }
} 

创建方法一般如下:

Outer.Inner inner = new Outer().new Inner();

在内部类的字节码文件内,有一个 Outer 类型的隐藏变量 Outer.this,指代外部类

因此,可以通过内部类来访问外部类的私密字段:

public class Outer {
    private final String id; // 此处为 private

    public Outer(String id) {
        this.id = id;
    }

    class Inner {
        public void printId() {
            // 可以通过 外部类.this.XXX 方式访问字段,方法等。
            System.out.println(Outer.this.id); 
            
        }
    }
}

public static void main(String[] args) {
        Outer.Inner inner = new Outer("id1").new Inner();

        inner.printId(); // 输出 "id1"
}

静态内部类

顾名思义:

class Outer {
    static class Inner {
        // 代码
    }
}

不需要先创建外部类,可以直接创建。

Outer.Inner inner = new Outer.Inner();

也许有点抽象,但是静态内部类并太类似静态字段。

Outer.Inner inner1 = new Outer.Inner();
Outer.Inner inner2 = new Outer.Inner();

System.out.println(inner1) // 输出 Outer$Inner@A
System.out.println(inner2) // 输出 Outer$Inner@B

System.out.println(inner1 == inner2) // 输出 false

同时,静态外部类无法访问外部类的非静态字段:

class Outer {
    private final String id = "id1";

    // 此处有 static 修饰符
    static class Inner {
        // 无法运行
        System.out.println(Outer.this.id)
    }
}

局部内部类

方法内部的类,说实话感觉没啥用。

只能在方法内部使用,但局部内部类可以访问外部类的成员。

void method() {
    // 代码...
    class Inner {
        // 内部代码...
    }

    // 直接创建就行
    Inner inner = new Inner();
}

匿名内部类

没名字的实例吧。

但是比局部内部类有用,好像后面的lambda就是匿名内部类的简化。

匿名内部类的创建方法,不过目前没法使用:

class Sample{ 
    // 代码 ...
}

void main() {
    new Sample() {
        // 代码...
    }
}

需要一个方法去调用匿名内部类:

class Sample{ 
    void method() {
        // 代码...
    }
}

void main() {
    call(new Sample() {
        void method() {
            // 代码...
        }
    });
}

void call(Sample s) {
    s.method();
}

Lambda 表达式

lambda表达式和匿名内部类类似,但是lambda表达式只能用来简化函数式接口(FunctionalInterface)

以下是用内部类实现的方法:

// 函数式接口
@FunctionalInterface
interface Inter {
    void method();
}

void main() {
    call(
        // Inter 匿名内部类
        new Inter() {
            @Override
            public void method() {
                System.out.println("Hello");
            }
        }
    );
}

void call(Inter inter) {
    inter.method()
}

用lambda表达式就可以把中间的匿名内部类替换掉:

void main() {
    call(
        // 接口的 method 是无参数方法,所以就只有一个括号。
        () -> {
            System.out.println("Hello");
        }
    );
}

当然,接口内的方法可以添加参数:

// 函数式接口
@FunctionalInterface
interface Inter {
    void method(String str);
}

void main() {
    call(
        // 括号内填参数。
        (str) -> {
            System.out.println(str);
        }
    );
}

void call(Inter inter) {
    inter.method("Hello")
}

如上,参数都能一一对上,且表达式内部只有一个方法的调用话,就可以用方法引用(MethodReference)

void main() {
    call(System.out::println); // 输出 "Hello"
}

void call(Inter inter) {
    inter.method("Hello")
}
苟延残喘的小博客
使用 Hugo 构建
主题 StackJimmy 设计