Java


Java

数据类型

  • 基本类型:
    byte/8
    char/16
    short/16
    int/32
    float/32
    long/64
    double/64
    boolean/~

  • 包装类型:
    基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。

    Integer x = 2;     // 装箱 调用了 Integer.valueOf(2)
    int y = x;         // 拆箱 调用了 X.intValue()
    
  • 缓存池:
    new Integer(123) 与 Integer.valueOf(123) 的区别在于:
    new Integer(123) 每次都会新建一个对象;
    Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。

    Integer x = new Integer(123);
    Integer y = new Integer(123);
    System.out.println(x == y);    // false
    Integer z = Integer.valueOf(123);
    Integer k = Integer.valueOf(123);
    System.out.println(z == k);   // true
    

    valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。

    public static Integer valueOf(int i) {
      if (i >= IntegerCache.low && i <= IntegerCache.high)
          return IntegerCache.cache[i + (-IntegerCache.low)];
      return new Integer(i);
    }
    

    String

  • 概览:
    String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)
    在 Java 8 中,String 内部使用 char 数组存储数据。

    public final class String
      implements java.io.Serializable, Comparable<String>, CharSequence {
      /** The value is used for character storage. */
      private final char value[];
    }
    

    在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。
    ```
    public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;

}

value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
- 不可变的好处:     
1. 可以缓存 hash 值:        
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。        
2. String Pool 的需要:         
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。       
3. 安全性:        
String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。           
4. 线程安全:         
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。            
- String, StringBuffer and StringBuilder:         
1. 可变性:        
String 不可变         
StringBuffer 和 StringBuilder 可变     
2. 线程安全:         
String 不可变,因此是线程安全的         
StringBuilder 不是线程安全的           
StringBuffer 是线程安全的,内部使用 synchronized 进行同步      
## 运算
- 参数传递:   
Java 的参数是以值传递的形式传入方法中,而不是引用传递。     
以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。在将一个参数传入一个方法时,本质上是将对象的地址以值的方式传递到形参中。        

public class Dog {

String name;

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

String getName() {
    return this.name;
}

void setName(String name) {
    this.name = name;
}

String getObjectAddress() {
    return super.toString();
}

}

在方法中改变对象的字段值会改变原对象该字段值,因为引用的是同一个对象。     

class PassByValueExample {
public static void main(String[] args) {
Dog dog = new Dog(“A”);
func(dog);
System.out.println(dog.getName()); // B
}

private static void func(Dog dog) {
    dog.setName("B");
}

}

## 关键字
- final:  
1. 数据:    
声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。        
对于基本类型,final 使数值不变;      
对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。            
2. 方法:     
声明方法不能被子类重写。        
private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。      
3. 类:    
声明类不允许被继承。        
- static:  
1. 静态变量:    
静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。    
实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。     

public class A {

private int x;         // 实例变量
private static int y;  // 静态变量

public static void main(String[] args) {
    // int x = A.x;  // Non-static field 'x' cannot be referenced from a static context
    A a = new A();
    int x = a.x;
    int y = A.y;
}

}

2. 静态方法:        
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。     

public abstract class A {
public static void func1(){
}
// public abstract static void func2(); // Illegal combination of modifiers: ‘abstract’ and ‘static’
}

只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字,因为这两个关键字与具体对象关联。  

public class A {

private static int x;
private int y;

public static void func1(){
    int a = x;
    // int b = y;  // Non-static field 'y' cannot be referenced from a static context
    // int b = this.y;     // 'A.this' cannot be referenced from a static context
}

}

3. 静态语句块:    
静态语句块在类初始化时运行一次。      

public class A {
static {
System.out.println(“123”);
}

public static void main(String[] args) {
    A a1 = new A();
    A a2 = new A();
}

}

4. 静态内部类:        
非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。     

public class OuterClass {

class InnerClass {
}

static class StaticInnerClass {
}

public static void main(String[] args) {
    // InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
    OuterClass outerClass = new OuterClass();
    InnerClass innerClass = outerClass.new InnerClass();
    StaticInnerClass staticInnerClass = new StaticInnerClass();
}

}

## Object 通用方法
- 概览:  

public native int hashCode()

public boolean equals(Object obj)

protected native Object clone() throws CloneNotSupportedException

public String toString()

public final native Class<?> getClass()

protected void finalize() throws Throwable {}

public final native void notify()

public final native void notifyAll()

public final native void wait(long timeout) throws InterruptedException

public final void wait(long timeout, int nanos) throws InterruptedException

public final void wait() throws InterruptedException

```

继承

  • 访问权限:
    public:
    具有最大的访问权限,可以访问任何一个在classpath下的类、接口、异常等。它往往用于对外的情况,也就是对象或类对外的一种接口的形式。
    protected:
    主要的作用就是用来保护子类的。它的含义在于子类可以用它修饰的成员,其他的不可以,它相当于传递给子类的一种继承的东西。
    default:
    有时候也称为friendly,它是针对本包访问而设计的,任何处于本包下的类、接口、异常等,都可以相互访问,即使是父类没有用protected修饰的成员也可以。
    private:
    访问权限仅限于类的内部,是一种封装的体现,例如,大多数成员变量都是修饰符为private的,它们不希望被其他任何外部的类访问。
  • 抽象类与接口:
  1. 抽象类:
    抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类。
    抽象类和普通类最大的区别是,抽象类不能被实例化,只能被继承。
  2. 接口:
    接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
    从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类,让它们都实现新增的方法。
    接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。从 Java 9 开始,允许将方法定义为 private,这样就能定义某些复用的代码又不会把方法暴露出去。
    接口的字段默认都是 static 和 final 的。
  3. 比较:
    从设计层面上看,抽象类提供了一种 IS-A 关系,需要满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
    从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
    接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
    接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。

    Java 与 C++ 的区别

    Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即支持面向对象也支持面向过程。
    Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
    Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
    Java 支持自动垃圾回收,而 C++ 需要手动回收。
    Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
    Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
    Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。

    JRE or JDK

    JRE:Java Runtime Environment,Java 运行环境的简称,为 Java 的运行提供了所需的环境。它是一个 JVM 程序,主要包括了 JVM 的标准实现和一些 Java 基本类库。
    JDK:Java Development Kit,Java 开发工具包,提供了 Java 的开发及运行环境。JDK 是 Java 开发的核心,集成了 JRE 以及一些其它的工具,比如编译 Java 源码的编译器 javac 等。

    Java中实现多态的方式

    1、接口实现;
    2、继承父类进行方法重写;
    3、同一个类中进行方法重载。
    多态存在的必要条件:
    1、要有继承;
    2、要有重写;
    3、父类引用指向子类对象。
    多态的好处:
    1、可替换性(substitutability)。
    多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
    2、可扩充性(extensibility)。
    多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
    3、接口性(interface-ability)。
    多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
    4、灵活性(flexibility)。
    它在应用中体现了灵活多样的操作,提高了使用效率。
    5、简化性(simplicity)。
    多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

文章作者: FFFfrance
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 FFFfrance !