Java notes (continuos updating)
z

java notes

  • Java丢弃了C++中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。

  • Java语言不使用指针,而是引用。并提供了自动的废料收集。

  • Java语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为implements)。

  • 在基本的Java应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。

  • Java的强类型机制、异常处理、垃圾的自动收集等是Java程序健壮性的重要保证。

  • Java编译器是用Java实现的,Java的运行环境是用ANSI C实现的。

  • Java平台中的Java解释器对这些字节码进行解释执行,执行过程中需要的类在联接阶段被载入到运行环境中。

  • 线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为Thread(Runnable)的构造子将一个实现了Runnable接口的对象包装成一个线程,其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程。值得注意的是Thread类已经实现了Runnable接口,因此,任何一个线程均有它的run方法,而run方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为synchronized)。

  • 代码风格

    • 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
    • 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
    • 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记Java是大小写敏感的),文件名的后缀为.java。(如果文件名和类名不相同则会导致编译错误)。
    • 主方法入口:所有的Java 程序由**public static void main(String []args)**方法开始执行。
  • 所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始

  • 合法标识符举例:age、$salary、_value、__1_value

  • 非法标识符举例:123abc、-salary

  • 数组是储存在堆上的对象,可以保存多个同类型变量。

  • Java 对象和类

    • 类是对象的模板,对象是类的实例。
    • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。局部变量是在栈上分配的。局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。访问修饰符不能用于局部变量;
    • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;堆中存储。
    • 类变量、静态变量:类变量也声明在类中,方法体之外,但必须声明为static类型。无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。静态变量在程序开始时创建,在程序结束时销毁。大多数静态变量声明为public类型。
    • 构造方法:构造方法的名称必须与类同名,一个类可以有多个构造方法。
    • 声明:声明一个对象,包括对象名称和对象类型。
    • 实例化:使用关键字new来创建一个对象。
    • 初始化:使用new创建对象时,会调用构造方法初始化对象。
    • 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
    • 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
  • Java包

    • 包主要用来对类和接口进行分类。
  • 数据类型

    • 内置数据类型

      • byte:byte 数据类型是8位、有符号的,以二进制补码表示的整数
        • 最小值是 -128(-2^7);
        • 最大值是 127(2^7-1);
        • 默认值是 0;
        • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
        • 例子:byte a = 100,byte b = -50。
      • short:
        • short 数据类型是 16 位、有符号的以二进制补码表示的整数
        • 最小值是 -32768(-2^15);Short.MIN_VALUE
        • 最大值是 32767(2^15 - 1);
        • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
        • 默认值是 0;
        • 例子:short s = 1000,short r = -20000
      • int:
        • int 数据类型是32位、有符号的以二进制补码表示的整数;
        • 最小值是 -2,147,483,648(-2^31);Integer.MIN_VALUE
        • 最大值是 2,147,483,647(2^31 - 1);
        • 一般地整型变量默认为 int 类型;
        • 默认值是 0 ;
        • 例子:int a = 100000, int b = -200000。
      • Long
        • long 数据类型是 64 位、有符号的以二进制补码表示的整数;
        • 最小值是 -9,223,372,036,854,775,808(-2^63);
        • 最大值是 9,223,372,036,854,775,807(2^63 -1);
        • 这种类型主要使用在需要比较大整数的系统上;
        • 默认值是 0L;
        • 例子: long a = 100000L,Long b = -200000L。
          “L”理论上不分大小写,但是若写成”l”容易与数字”1”混淆,不容易分辩。所以最好大写。
      • float
        • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
        • float 在储存大型浮点数组的时候可节省内存空间;
        • 默认值是 0.0f;
        • 浮点数不能用来表示精确的值,如货币;
        • 例子:float f1 = 234.5f。
      • double
        • double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
        • 浮点数的默认类型为double类型;
        • double类型同样不能表示精确的值,如货币;
        • 默认值是 0.0d;
        • 例子:double d1 = 123.4。
      • boolean
        • boolean数据类型表示一位的信息;
        • 只有两个取值:true 和 false;
        • 这种类型只作为一种标志来记录 true/false 情况;
        • 默认值是 false;
        • 例子:boolean one = true。
      • char
        • char类型是一个单一的 16Unicode 字符;
        • 最小值是 \u0000(即为0);Character.MIN_SIZE
        • 最大值是 \uffff(即为65,535);
        • char 数据类型可以储存任何字符;
        • 例子:char letter = ‘A’;。
    • 引用变量

      • 指向对象的变量是引用变量
      • 对象、数组都是引用数据类型
      • 所有引用类型的默认值都是null
      • 一个引用变量可以用来引用任何与之兼容的类型。
      • Dog myDog = new Dog(“hey”);
    • 常量

      • final修饰

      • 通常使用大写字母表示常量

      • final double PI = 3.1415;

      • ```java
        int decimal = 100;
        int octal = 0144;
        int hexa = 0x64;

        1
        2
        3
        4
        5

        * 自动类型转换

        * ```java
        byte,short,char—> int —> long—> float —> double
      • 浮点数到整数的转换是通过舍弃小数得到 (int) -45.6f == -45

  • 访问控制修饰符

    • default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。

    • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

    • public : 对所有类可见。使用对象:类、接口、变量、方法

    • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

      修饰符 当前类 同一包内 子孙类 其他包
      public Y Y Y Y
      protected Y Y Y N
      default Y Y N N
      private Y N N N
    • 父类中声明为 public 的方法在子类中也必须为 public。

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

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

    • final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。类中的 final 方法可以被子类继承,但是不能被子类修改。

    • abstract 修饰符,用来创建抽象类和抽象方法,抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类。抽象方法不能被声明成 final 和 static。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public abstract class SuperClass{
      abstract void m(); //抽象方法
      }

      class SubClass extends SuperClass{
      //实现抽象方法
      void m(){
      .........
      }
      }

    • synchronized 和 volatile 修饰符,主要用于线程的编程。synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

    • transient:

      • 序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。
    • volatile:

      • volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      public class MyRunnalbe implements Runnable {
      private volatile boolean active;
      public void run(){
      while(active){
      // do something
      }
      }
      public void stop(){
      active = false;
      }
      }
      // 这样的话,当两个线程一个调用run()方法时,一个调用stop时
      // 在没有被volatile修饰的情况下,第一个run不会终止
      // 但是在加上volatile修饰后,有一个调用stop,其他线程都会停止

    transient

    当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;

    //定义一个需要序列化的类

    class People implements Serializable{
    String name; //姓名
    transient Integer age; //年龄
    public People(String name,int age){
    this.name = name;
    this.age = age;
    }

    public String toString(){
    return "姓名 = "+name+" ,年龄 = "+age;
    }

    }

    public class TransientPeople {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
    People a = new People("李雷",30);
    System.out.println(a); //打印对象的值
    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d://people.txt"));
    os.writeObject(a);//写入文件(序列化)
    os.close();
    ObjectInputStream is = new ObjectInputStream(new FileInputStream("d://people.txt"));
    a = (People)is.readObject();//将文件数据转换为对象(反序列化)
    System.out.println(a); // 年龄 数据未定义
    is.close();
    }
    }

    运行结果如下:

    1
    2
    姓名 = 李雷 ,年龄 = 30
    姓名 = 李雷 ,年龄 = null

    volatile

    volatile可以用在任何变量前面,但不能用于final变量前面,因为final型的变量是禁止修改的。

    使用的场景之一,单例模式中采用DCL双锁检测(double checked locking)机制,在多线程访问的情况下,可使用volatitle修改,保证多线程下的可见性。缺点是性能有损失,因此单线程情况下不必用此修饰符。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Singleton{
    private volatile static Singleton instance = null;
    private Singleton() {
    }

    public static Singleton getInstance() {
    if(instance==null) {
    synchronized (Singleton.class) {
    if(instance==null)
    instance = new Singleton();
    }
    }
    return instance;
    }
    }