Java:语法速通

参考

菜鸟教程 java
JavaGuide

继承

class 父类 {
}
 
class 子类 extends 父类 {
}

在这里插入图片描述
继承的特性:

  • 子类拥有父类非private的属性和方法
  • 子类可以对父类进行扩展
  • 子类可以重写父类的方法
  • 使用extends只能单继承,使用implements可以变相的多继承,即一个类继承多个接口,如下。
public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}
  • 通过super关键字引用当前对象的父类,通过this关键字引用自身。
class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}
 
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}
  • 使用final关键字修饰的类不能被继承,但类内的属性和方法不是final的。使用final关键字修饰的方法不能被子类重写。
  • 子类不继承父类的构造器,只是调用,实例化子类对象时,先调用父类的构造器。若父类构造器有参,则子类构造器中需显式使用super调用父类构造器,若父类构造器无参,则系统自动调用。
/**
 * @author wuming
 * @date 2023-12-20 13:48
 * @description
 */

class SuperClass{
    private int n;
    SuperClass(){
        System.out.println("SuperClass 无参构造");
    }
    SuperClass(int n){
        System.out.println("SuperClass 有参构造" + n);
        this.n = n;
    }
}

class SubClass extends SuperClass{
    private int n;
    // 系统自动调用父类的无参构造函数
    SubClass(){
        System.out.println("SubClass 隐式调用父类无参构造");
    }
    SubClass(int n){
        super(n);
        System.out.println("SubClass 显式调用父类有参构造");
        this.n = n;
    }
}

public class ExtendTest {
    public static void main (String args[]){
        new SubClass();
        new SubClass(200);
    }
}

SuperClass 无参构造
SubClass 隐式调用父类无参构造
SuperClass 有参构造200
SubClass 显式调用父类有参构造

重写

重写指子类对父类允许子类访问的方法的实现进行重写的过程,重写的函数名、返回值和形参与父类中的方法保持一致,具体功能可自己实现。

  • 子类重写的方法的访问权限不能比父类中被重写的方法更低。
  • 在异常处理方面,不允许子类抛出比父类方法更宽泛的异常。
  • 声明为final、static的方法和构造方法不能被重写。

重载

重载是指在一个类里面方法名字相同但参数个数或类型不同,返回类型可以相同也可以不同。

基本类型与包装类型

一共有byte short int long char float double boolean八种基本类型,分别对应八种包装类型,有如下不同点。

  • 用途:一般使用基本类型定义常量和局部变量,而在方法参数和对象属性中使用包装类型。
  • 存储方式:基本数据类型的局部变量存放在java虚拟机栈中的局部变量表中,未被static修饰的基本类型成员变量存放在Java虚拟机的堆中。包装类型属于对象类型,存在于堆中。
  • 占用空间:基本类型的占用空间非常小。
  • 默认值:作为成员变量的包装类型默认值是null,基本类型各自有各自的默认值不为null。
  • 比较方式:对于基本类型,使用 == 可作值比较,对于包装类型,使用 == 是地址比较,使用equals方法才是值比较。

包装类型的缓存机制

包装类型大部分使用了缓存机制提升性能,如Byte Short Integer Long四种包装类型默认创建了数值 [-128, 127] 相应类型的缓存数据。
Integer缓存源码如下:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static {
        // high value may be configured by property
        int h = 127;
    }
}

看以下代码

Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);

第一行会发生装箱,等价于Integer i1 = Integer.valueOf(40),而40在缓存区间中,所以 i1使用缓存中的对象,而 i2 是新创建的对象,使用 == 比较时,比较的是地址,结果为false。

自动拆装箱

Integer i = 10;  //装箱
int n = i;   //拆箱

静态方法为什么不能调用非静态成员

静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过对象访问。

引用拷贝、深拷贝和浅拷贝

博客园

Object类

Object类是所有类的父类,提供以下11个方法

/**
 * native 方法,用于返回当前运行时对象的 Class 对象,使用了 final 关键字修饰,故不允许子类重写。
 */
public final native Class<?> getClass()
/**
 * native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。
 */
public native int hashCode()
/**
 * 用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。
 */
public boolean equals(Object obj)
/**
 * native 方法,用于创建并返回当前对象的一份拷贝。
 */
protected native Object clone() throws CloneNotSupportedException
/**
 * 返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。
 */
public String toString()
/**
 * native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
 */
public final native void notify()
/**
 * native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
 */
public final native void notifyAll()
/**
 * native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。
 */
public final native void wait(long timeout) throws InterruptedException
/**
 * 多了 nanos 参数,这个参数表示额外时间(以纳秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 纳秒。。
 */
public final void wait(long timeout, int nanos) throws InterruptedException
/**
 * 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
 */
public final void wait() throws InterruptedException
/**
 * 实例被垃圾回收器回收的时候触发的操作
 */
protected void finalize() throws Throwable { }

hashCode

hashCode()的作用是获取哈希码(int整数),定义在Object类中。
HashSet 如何检查重复:当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashCode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashCode 值作比较,如果没有相符的 hashCode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashCode 值的对象,这时会调用 equals() 方法来检查 hashCode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
因为两个对象的hashCode相等不等价于两个对象相等(碰撞),所以在快速使用完hashCode判别后若相等,还需使用equals判断。

为什么重写 equals() 时必须重写 hashCode() 方法?

因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。

如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象,hashCode 值却不相等。

String、StringBuffer和StringBuilder

String是不可变的,在String类中,保存字符串的数组被final修饰,且为私有,没有提供修改字符串的方法。
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰,最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的方法比如 append 方法。

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    //...
}

线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

对于三者使用的总结:
操作少量的数据: 适用 String
单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

在 Java 9 之后,String、StringBuilder 与 StringBuffer 的实现改用 byte 数组存储字符串,Latin-1 编码方案下,byte 占一个字节(8 位),char 占用 2 个字节(16),节省一半的内存空间。如果字符串中包含的汉字超过 Latin-1 可表示范围内的字符,byte 和 char 所占用的空间是一样的。

字符串对象通过“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。

不过,在循环内使用“+”进行字符串的拼接的话,存在比较明显的缺陷:编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象,如果直接使用 StringBuilder 对象进行字符串拼接的话,就不会存在这个问题了。

String 中的 equals 方法是被重写过的,比较的是 String 字符串的值是否相等。 Object 的 equals 方法是比较的对象的内存地址。

字符串常量池

字符串常量池是JVM为了提升性能为String类专门开辟的内存区域,主要为了避免字符串的重复创建。

// 在堆中创建字符串对象”test“
// 将字符串对象”test“的引用保存在字符串常量池中
String aa = "test";
// 直接返回字符串常量池中字符串对象”test“的引用
String bb = "test";
System.out.println(aa==bb);// true

String s1 = new String(“abc”)创建了几个字符串对象

CSDN

String.intern()

CSDN

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值