《Java编程思想》笔记3:初始化,访问控制

本篇关注:初始化(第5章),访问控制(第6章)


初始化 Initialization

构造器 constructor

创建对象时被自动调用,名称与类名完全相同的特殊方法,用来执行初始化,没有返回值

Java中,创建和初始化是捆绑的。
new创造对象时,会为对象分配空间,并调用相应构造器。

默认构造器
又叫无参构造器。如果类中没有写,则编译器会自动创建。

class Rock {
    Rock() {       // 默认构造器
        ...
    }
}

可以修改为有参数

重载 Oveloading

用多种方式创建一个对象。参数列表必须独一无二。以返回值区分重载方法是行不通的。

class Tree {
    int height;
    
        Tree() {
        System.out.println("Planting a seed");
        height = 0;
}

    Tree(int initialHeight) {
        height = initialHeight;
        System.out.println("The new tree is " + height + " feet tall");
    }

    void info() {
        System.out.println("Tree is " + height + " feet tall");
    }

    void info(String string) {
        System.out.println(string + ": Tree is " + height + " feet tall");
    }
}
  1. 如果传入的数据类型(实际参数类型)小于方法中声明的形式参数类型,实际数据类型就会被提升。char型不同,如果无法找到接受char参数的方法,就会把char提升至int。
  2. 如果传入的实际参数较大,就得通过类型转换来执行窄化转换。
this

this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用
很容易在一条语句里对同一个对象执行多次操作。或者将其自身传递给外部方法。

在构造器中调用构造器
this加上参数列表,可以调用符合的构造器。

public class Flower {
    int petalCount = 0;
    String s = "initial value";
    Flower(int petals) {
        petalCount = petals;
        System.out.println("Constructor with int arg only");
    }
    Flower(String s, int petals) {
        this(petals);//call constructor 
        //! this(s);//can't call two
        this.s = s;
        System.out.println("Constructor with int & String args");
    }
    Flower() {
        this("hi", 47);
        System.out.println("Default constructor with no arg");
    }
}

这种调用必须处在构造器块中的起始处。
不可以同时调用两个构造器。
this.s 可以指代数据成员。
其他方法中不可以调用构造器。

成员初始化

基本数据类型都有默认的初值。对象引用的默认值是null。

声明变量的时候直接赋值,或者调用某方法为它赋值。
类的内部,变量定义的先后顺序决定了初始化的顺序。
变量定义于任意位置,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。

静态初始化只在必要时刻(静态对象被创建/静态数据被访问),在class对象首次加载的时候进行一次。

可以使用静态块组合多个静态初始化

static int a;
static int b;
static{
    a = 3;
    b = 4;
}

初始化顺序:先是静态对象,再是非静态对象。

构造器也属于静态方法。
对象创建过程:假设有个Dog类

  1. 首次创建Dog对象,或者首次访问Dog类的静态方法/数据时,定位Dog.class文件
  2. 载入Dog.class(创建Dog.class对象)。执行静态初始化,之后不会执行第二次。
  3. 用new Dog()创建对象时,在heap上分配内存空间
  4. 内存空间清零,Dog对象所有基本数据类型和引用变为默认值
  5. 执行程序中定义的初始化
  6. 执行构造器
可变参数列表

参数个数或类型不确定时
显式地创建以Object数组为参数的方法:

class A {}
public void printArray(Object[] args) {
    for(Object obj : args)
        System.out.print(obj + " ");
    System.out.println();
}
printArray(new Object[]{new Integer(47), new Float(3.14), new Double(11.11)});
printArray(new Object[]{"one", "two", "three"});
printArray(new Object[]{new A(), new A(), new A()});

定义可变参数列表:

public void printArray(Object... args) {
    for(Object obj : args)
        System.out.print(obj + " ");
    System.out.println();
}

类型确定:

public void printArray(int i, String... args) {}

适用于参数个数不确定的情况,java把可变参数当做数组处理。

  1. 只支持有一个可变参数,只能出现在参数列表的最后;
  2. ...前后有无空格都可以,args名字自定义。
  3. 方法中以数组的形式访问可变参数。
  4. 把0个参数传给可变参数列表也可以。
枚举类型 Enumerated types
public enum Spiciness {
    NOT, MILD, MEDIUM, HOT, FLAMING
}
public class SimpleEnum {
    public static void main(String[] args) {
        Spiciness spiciness = Spiciness.MEDIUM;
        System.out.println(spiciness);
        
        for(Spiciness s : Spiciness.values())
            System.out.println(s + ", ordinal " + s.ordinal());
    }
}

可以把enum看成是一个类。一个数据类型。
通常枚举的元素命名全都大写,多个单词用_隔开。
但是enum不能使用extends继承其他类,因为enum已经继承了java.lang.Enum(Java是单一继承)
枚举类中每个值都被映射到protected Enum(String name, int ordinal)
ordinal():获取枚举常量的声明顺序
values():获取一个数组,按声明顺序

与switch组合绝佳,因为switch是在有限的可能值集合中选择

switch(degree) {
    case NOT:    
        System.out.println("not spicy at all");
        break;
    case MILD:
    case MEDIUM:    
        System.out.println("a little hot");
        break;
    case HOT:
    case FLAMING:
    default:    
        System.out.println("may be to hot");
        break;
}

EnumSet
提供了Set接口的实现

EnumSet allSpiciness = EnumSet.allOf(Spiciness.class);
EnumSet partSpiciness = EnumSet.of(Spiciness.NOT, Spiciness.MEDIUM);

EnumMap
提供了Map接口的实现。键(key)是一个枚举类型

EnumMap enumMap = new EnumMap<>(Spiciness.class);
enumMap.put(Spiciness.NOT, "not spicy at all");
enumMap.put(Spiciness.MILD, "a little hot");
enumMap.put(Spiciness.HOT, "maybe too hot");
for(Spiciness s : Spiciness.values())
    System.out.println(s + " represents " + enumMap.get(s));

访问控制 Access control

.java文件被称为编译单元 compilation unit,或转译单元 translation unit
每个编译单元只能有一个public类
编译后产生同名的.class文件。Java的可运行程序就是一组.class文件(可打包为JAR)

package:声明一个包。位于除了注释外的第一行。
import:导入一个包。
包名:全部小写。通常是把自己的域名反过来。或者是机器上的class文件路径。
处于同路径且没有声明包名的class文件,会被看作隶属于该目录的默认包中。

如果import两个包,包含相同的类名。创建时就必须明确指明:
java.util.Vector v = new java.util.Vector()

类中成员(变量/方法)访问权限:

类内部 本包其他类 外部包子类 外部包其他类
public
protected
default
private

default:默认的包访问权限,不需要写出来。class Abc{ }

类的修饰:不可以是private和protected的。内部类可以。
不希望别人访问该类,可以把构造器设为private。但是public static成员可以被访问。
通常最好是把域保持为private,通过protected方法控制类的继承者的访问权限。

封装 encapsulation:把数据和方法包装进类中,隐藏具体实现。得到一个数据类型。


References:

吕龙宝的《Java编程思想》学习笔记

你可能感兴趣的:(《Java编程思想》笔记3:初始化,访问控制)