Java cheatsheet (III)

3.1. 环境变量的设置

一般需要设置如下的环境变量,形如:

set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_31
set PATH=%JAVA_HOME%\bin;%PATH%
set CLASSPATH=.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar

3.2. 引入类库的方法

1. 在文件系统中创建一个存放 java 包的文件夹,例如:D:\java\lib\
2. 将这个文件夹放到环境变量 CLASSPATH 中去;
set CLASSPATH=.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar;D:\java\lib
3. 创建自己的包路径文件结构:

创建目录 D:\java\lib\cn\easecloud\learn

4. 在自己的包目录下创建 java 类文件

创建文件 D:\java\lib\cn\easecloud\learn\MyClass.java

文件内容如下:

package cn.easecloud.learn;

public class MyClass {
    public myMethod() {
        // ...
    }
}

注意 package 语句的格式,要与包目录的路径相符。

然后就可以在同一个系统下调用这个自定义的类库了。

3.3. 关于包与公共类的权限

  1. 每个编辑单元(文件)至多只能由一个 public 类;
  2. public 类的名称必须连大小写与编译单元的文件名相匹配;
  3. 如果编辑单元内完全不带 public 类(不常见),可以随意对文件命名;
  4. 引入包之后,只能使用包里面的公共类,其他的类对于外部不可见;

3.4. 类成员的包访问权限(重要)

对于一个包内的类成员,如果在不加修饰请情况下(如下例 myMember):

package cn.easecloud.learn;

public class MyClasss {
    int myMember = 0;
}

这个成员即具有“包访问权限”(friendly),也就是说当前包中的所有其他类对那个成员都有访问权限,但是对于包之外的所有类,这个成员是 private。

3.5. toString() 方法

每一个非基本类型的对象都有一个 toString() 方法,而且当编译器需要一个 String 而你却只有一个对象时,该方法便会被调用:

注意 toString 方法的签名,必须是 public,而且传入 0 个参数,返回一个 String 对象。

import java.util.*;

class MyClass {
    public String toString() {
        System.out.println("MyClass.toString() method is called!");
        return "";
    }
}

public class Program {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        System.out.println(obj);  // 这里调用一次 toString() 方法
    }
}

3.6. 对象成员初始化

一个对象可能有多个引用类型的成员(字段),但是编译器并不会简单地为每一个引用创建默认对象,而是为其赋一个 null 值。

可以通过以下方法实现:

  1. 在定义(成员)对象的地方,这样可以在类的构造器之前执行这些构造;
  2. 在构造函数中;
  3. 在使用对象之前(惰性初始化);
  4. 使用实例初始化;
class Person {
    Person() {
        System.out.println("Person was constructed;");
    }
}

class MyClass {
    Person person = new Person();  // 第一种方式
    public MyClass() {
        this.person = new Person();  // 第二种方式
        System.out.println("1. MyClass was constructed;");

    }
    public someMethod() {
        // 第三种方式,惰性初始化,其实也就是不初始化,让其为 null
        if(this.person == null) {
            this.person = new Person();
        }
    }
    { // 第四种方式,实例初始化,在类定义中放置一个花括号,然后在花括号中进行初始化
      // 类似于 cheatsheet-2 中提到的静态子句
        person = new Person();
    }
}

3.7. 完整的继承范例

//: Children.java

class Person {
    private Date birthday; 
    public String name = "Unnamed";
    public Boolean gender;
    public void eat() {
    }
    public void sleep() {
    }
    public String toString() {
        return name;
    }
    public static void main(String[] args) {
        System.out.println("Person main;");
    }
}

public class Children extends Person {
    public void sleep() {
        // 重写方法
    }
    public cry() {
        // 添加新的方法
    }
    // 真正的入口在这里
    public static void main(String[] args) {
        System.out.println("Children main;");
        // 创建对象
        Children chlid = new Children();
        // 调用派生类方法
        child.cry();
        // 调用基类方法
        child.eat();
        // 调用基类静态方法
        Person.main(args);
    }
}
///:~

3.8. 一般性继承规则

把所有的数据成员指定为 private,将所有的方法指定为 public。

3.9. 继承类的构造过程

在默认的情况下,当一个派生类被构造的时候,会按照继承链从基类开始一层一层依次调用它们的构造函数。

如果父类的构造器有多个版本(可能是带参数),那么可以用 super(...) 语句来显式调用父类的构造函数。

注意 super(...) 语句必须是构造器的第一个语句(如果有),其参数即为所调用父类构造器的函数签名。如此,父类的构造器就只会调用这一个版本(默认的版本就不调用了)。

import java.util.*;

class Art {
    Art() { System.out.println("Art constructor"); }
}

class Drawing extends Art {
    Drawing() { System.out.println("Drawing constructor"); }
    Drawing(int a) { System.out.println("Drawing constructor(int)"); }
}

class Cartoon extends Drawing {
    Cartoon() { super(0); System.out.println("Cartoon constructor"); }
}

public class Program {
    public static void main(String[] args) {
        Cartoon x  = new Cartoon();
    }
}

/* output
Art constructor
Drawing constructor(int)
Cartoon constructor
*/

3.10. 代理

TODO: 简要来说,就是组合一个功能类,然后将所有功能类的方法挨个在父类中级联,但由于比较偏门,而且书中说不支持,先行跳过。

3.11. @Override 注解

如果在类的方法前面加上 @override 注解,以声明此方法为覆写,而不是重载;

覆写的含义是,基类或者接口里面是有这一个方法的(签名一致),这只是当前派生类对其的实现。

如果基类里面是没有定义这一个接口,则这个方法属于“重载”,即为类添加新的方法,而不是覆写。

因此,如果想要对基类或者接口原有的方法改写一个实现,语义上应当为其加上 @Override 注解,编译器会检查,如果基类或接口没有这个签名,则会报错。

class MyClass {

    @Override  // 这种情况因为基类有 toString() 方法,不会报错
    public String toString() {
        return "...";
    }

    @override  // 这种情况因为基类没有 toString(String) 方法,会报错
    public String toString(String s) {
        return "...";
    }

}

3.12. final 字段

对类的成员字段可以指定 final 标记,如此一来:

  1. 如果是基本数据,那么 final 指定的内容不可改变(可认为是一个编译时常量);
  2. 如果是引用类型,那么这个 final 产生的引用不能改变(而被引用的对象本身可以改变);

final 标记也可以对 static 字段来描述。

空白 final: 如果 final 定义的字段没有赋予初始值,那么这个字段必须在初始化的时候被赋值(在构造函数中),并且在赋予初始值之后就不可以再改变。

3.13. final 参数

对方法的参数指定 final 标记,则该参数不可改变。

3.14. final 方法

final 修饰的方法在继承类中不可被覆盖。

private 方法隐式指定属于 final 类型。

3.15. final 类

final 类不可继承


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/02/java-cheatsheet-3.html【Java cheatsheet (III)】

发表评论

电子邮件地址不会被公开。 必填项已用*标注