《Java疯狂讲义-Chap6面向对象下》

1.final成员变量
final修饰的成员变量必须由程序员显示的指定初始值。
final修饰的类变量、实例变量能指定初始值的地方如下:
- 类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地方中的其中之一指定。
- 实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方中的其中之一指定。
如果打算在构造器、初始化块中对final成员变量进行初始化,则不要在初始化之前就访问成员变量的值。

2.final局部变量
系统不会对局部变量进行初始化,局部变量必须由程序员显示初始化。因此使用final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值。
如果final修饰的局部变量在定义时没有指定默认值,则可以在后面代码中对该final变量赋初始值,但只能一次,不能重复赋值;如果final修饰的局部变量在定义时已经指定默认值,则后面代码中不能再对该变量赋值。

3.final修饰基本类型变量和引用类型变量的区别
当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,fianl只保证这个应用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。

4.不可变(immutable)类
不可变类的意思是创建该类的实例后,该实例的实例变量是不可改变的。Java提供的8个包装类和String类都是不可变类。
如果需要创建自定义的不可变类,可遵守如下规则:
- 使用private和final修饰符来修饰该类的成员变量
- 提供带参数构造器,用于根据传入参数来初始化类例的成员变量
- 仅为该类的成员变量提供getter方法,不要为该类的成员变量提供setter方法,因为普通方法无法修改final修饰的成员变量
- 如果有必要,重写Object类的hashCode()和equals()方法。equals()方法根据关键成员变量来作为两个对象是否相等的标准,除此之外,还应该保证两个用equals()方法判断为相等的对象的hashCode()也相等。

例:定义不可变类Address

public class Address {
    private final String detail;
    private final String postCode;

    public Address() {
        this.detail = "";
        this.postCode = "";
    }

    public Address(String detail, String postCode) {
        this.detail = detail;
        this.postCode = postCode;
    }

    public String getDetail() {
        return this.detail;
    }

    public String getPostCode() {
        return this.postCode;
    }

    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (object != null && object.getClass() == Address.class) {
            Address address = (Address) object;
            if (address.getDetail().equals(this.getDetail())
                    && address.getPostCode().equals(this.getPostCode())) {
                return true;
            }
        }
        return false;
    }

    public int hashCode() {
        return detail.hashCode() + postCode.hashCode();
    }
}

5.抽象方法和抽象类
抽象方法和抽象类的规则如下:
- 抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体
- 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例
- 抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5中成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用
- 含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类

6.内部类
根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例等。总之,不允许在外部类的静态成员中直接使用非静态内部类。
非静态内部类里不能有静态方法、静态成员变量、静态初始化块。
静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。
静态内部类是外部类的一个静态成员,因此外部类的所有方法、所有初始化块中可以使用静态内部类来定义变量、创建对象等。
Java还允许在接口里定义内部类,接口里定义的内部类默认使用public static修饰,也就是说,接口内部类智能是静态内部类。如果为接口内部类指定访问控制符,则只能指定public访问控制符;如果定义接口内部类时省略访问控制符,则该内部类默认是public访问控制权限。

6.Lambda表达式
Lambda表达式的主要作用就是代替匿名内部类的繁琐语法。它有三部分组成:
- 形参列表。形参列表允许省略形参类型。如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略。
- 箭头(->)。必须通过英文中划线号和大于符号组成。
- 代码块。如果代码块只包含一条语句,Lambda表达式允许省略代码块的花括号,那么这条语句就不要用花括号表示语句结束。Lambda代码块只有一条return语句,甚至可以省略return关键字。Lambda表达式需要返回值,而它的代码块中仅有一条省略了return的语句,Lambda表达式会自动返回这条语句的值。

例:


public interface Eatable {
    void taste();   
}

public interface Flyable {
    void fly(String weather);
}

public interface Addable {
    int add(int a, int b);
}



public class LambdaQs {

    public void eat(Eatable e){
        Test.printInfoMethod(e);
        e.taste();
    }

    public void drive(Flyable f){
        Test.printInfoMethod("我正在驾驶:" + f);
        f.fly("【碧空如洗的晴日】");
    }

    public void test(Addable add){
        Test.printInfoMethod("5和3的和为:" + add.add(5, 3));
    }

    public static void main(String[] args){
        LambdaQs lQs = new LambdaQs();
        lQs.eat(()->Test.printInfoMethod("苹果的味道不错"));
        lQs.drive(weather->
                {
                    Test.printInfoMethod("今天天气是:" + weather);
                    Test.printInfoMethod("直升机飞行平稳");
                });
        lQs.test((a, b)->a+b);
    }
}

解析:上面程序中的eat方法使用Lambda表达式相当于不带形参的匿名方法,由于该Lambda表达式的代码块只有一行代码,因此可以省略代码块的花括号;调用drive方法使用Lambda表达式相当于不带形参的匿名方法,由于该Lambda表达式的形参列表只有一个形参,因此省略了形参列表的圆括号;调用test方法使用Lambda表达式的代码块中只有一行语句,这行语句的返回值将作为该代码块的返回值。

7.Lambda表达式与函数是接口
Lambda表达式的类型,也被称为“目标类型(target type)”,Lambda表达式的目标类型必须是“函数式接口(functional interface)”。函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值