美文网首页Java学习笔记程序员
《Java编程思想》笔记3:初始化,访问控制

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

作者: 992134d3a7cd | 来源:发表于2017-06-07 09:04 被阅读40次

    本篇关注:初始化(第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 <Flower(int petals)>
            //! 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<Spiciness, String> 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:初始化,访问控制

        本文链接:https://www.haomeiwen.com/subject/strofxtx.html