笔记111111111111

162 阅读11分钟

内部类

内部类是定义在另一个类(外部类/外围类)中的类,内部类的使用原因:可以对同一个包中的其它类隐藏(局部/匿名内部类位于类的局部位置上,对外界完全隐藏,而成员内部类和静态内部类通过访问权限符private、protected来控制是否对外界隐藏);内部类方法可以访问定义这个类的作用域中的数据,包括原有的私有数据。内部类在设计具有相互协作关系的类集合时很有用。

外围类的引用在非静态内部类的构造器中设置(编译器会修改内部类构造器,但是编译器不会修改静态内部类的构造器)。内部类是一个编译器现象,与虚拟机无关,,编译器会把内部类转换为名为:“外部类名$内部类名”的类文件。

为什么内部类可以访问外部类的私有数据:编译器在外部类中添加了静态方法用于访问外部类的字段,在内部类中访问外部类数据实际会调用:外部类.静态方法名(外部类引用)。

分类定义特点
局部内部类定义在外部类的局部位置上(方法、代码块中),且有类名对外界完全隐藏,只有这个方法、代码块中知道。可以访问局部变量。
匿名内部类定义在外部类的局部位置上(方法、代码块中),且无类名是局部内部类的延伸,当只想创建类的一个对象时使用。创建匿名内部类对象的语法为:new 抽象类/接口(构建参数) {   重写抽象类或接口中的方法}
成员内部类定义在外部类的成员位置上(属性、方法等),且无static修饰 
静态内部类定义在外部类的成员位置上(属性、方法等),且无static修饰只要内部类不需要访问外部类对象时,也就是不需要生成外部类对象引用时,就应该使用静态内部类

访问方式:内部类访问外部类的成员:都是直接访问,有个区别是静态内部类只能访问静态成员。

外部类访问内部类的成员:创建对象再访问(需要注意,局部内部类和匿名内部类需要在作用域内才能访问,静态内部类的静态成员可以直接访问而不用创建对象)

外部其他类访问内部类:不能访问局部内部类和匿名内部类,访问成员内部类:外部类对象.new 内部类名() 或者外部类提供一个访问内部类方法;访问静态内部类:通过外部类名.内部类名或者外部类提供一个访问内部类方法。

 

内部类使用场景:1、当某个类除了它的外部类,不再被其他的类使用时。2、解决一些非面向对象的语句块如try…catch…finally…,比如数据库中的连接问题。3、一些多算法场合。4、适当使用内部类,使得代码更加灵活和富有扩展性。5、当我们希望一个类必须继承多个抽象或者具体的类时,就只能用内部类来实现多重继承(内部类可以继承一个与外部类无关的类,从而保证内部类的独立性。正是基于这一点,多重继承才会成为可能。)。

 

 

接口

接口不是类,接口中的所有方法自动是public方法,接口没有实例(不能使用new运算符实例化一个接口,但可以声明一个接口变量),可以看成是没有实例字段的抽象类,

属性:接口字段总是public static final(不用声明),接口的方法都是public abstract的(可以再加static,jdk9开始可以为private的static或者实例方法),不建议使用只定义常见而不定义方法的接口(虽然有,但是不建议)。一个类只能继承一个类,但可实现多个接口。

接口中可以定义静态方法,但不建议,一般是将静态方法放在接口的伴随类中,比如Collection/Collections。

为接口增加默认方法(default)可以保证源代码的兼容性。

解决默认方法冲突:超类优先(类优先原则,超类方法优先于接口的默认方法),接口冲突必须覆盖这个方法解决冲突(实现的接口中出现两个同名且参数类型相同的方法)

 

clone方法

Java 中的对象拷贝分为深拷贝和浅拷贝,浅拷贝:基本数据类型的成员变量拷贝值,引用类型的成员变量拷贝引用地址;深拷贝:基本数据类型的成员变量拷贝值,引用类型的成员变量递归的调用 clone() 方法。

java中的浅拷贝:实现Cloneable接口,将clone方法定义为public,在clone方法中调用super.clone();

java中的深拷贝:实现Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象,还要将该类中的引用变量也clone出来。

实现完全的深复制是很难的,因为引用变量中可能还存在别的引用变量。

clone和new的区别:

(1)在java中clone()与new都能创建对象。

(2)clone()不会调用构造方法;new会调用构造方法。

(3)clone()创建对象并且将已有对象中所有属性值克隆;new是在JVM中申请一个空的内存区域,对象的属性值要通过构造方法赋值。

 

Lambda表达式

lambda表达式是一个可传递的代码块,可以在以后执行一次或者多次。

对于只有一个抽象方法的接口(函数式接口),当需要这个接口的对象时,可以提供一个lambda表达式。

语法:(参数1, 参数2) -> 表达式

参数类型如果可以推断出,可以忽略;只有一个参数,可以省略();无需指定返回值类型;表达式不允许一些分支不返回值。

lambda表达式中捕获的变量必须实际上是事实最终变量(变量初始化之后不会再为它赋新值)

方法引用

       object::instanceMethod,  Class::instanceMethod,   Class::staticMethod

 

       java是一种强类型语言,必须为每一个变量声明一种类型,在java中有8中基本类型(primitive type)。变量的声明应该尽可能地靠近变量第一次使用的地方,使用final指示常量(常量名习惯上使用全大写),static final修饰类常量。

       Java字符串就是Unicode字符序列。String类对象是不可变的(不能修改字符串的的单个字符),不过可以字符串变量,让它引用另外一个字符串。不可变字符串的优点在于:编译器可以让字符串共享。

       不用使用==运算符测试字符串的相等性,而是用equals()方法。

       字符串构建器StringBuilder(线程不安全,安全的是StringBuffer),append,toString()返回一个String对象.

       块(block)是由若干条java语句组成的复合语句,并用一对大括号括起来{}。

       带标签的break语句用于跳出多重嵌套的循环语句。

       数组一旦创建,长度就不可改变。

       foreach循环可以使用break退出。

       类之间的关系:依赖(uses-a,一个类的方法使用或者操纵另一个类的对象,就说一个类依赖另外一个类),聚合(has-a,一个类的对象包含另外一个类的对象),继承(is-a,子类的对象也是超类的对象,满足替换原则,程序中出现超类对象的地方都可以用子类对象替换)。

       对象变量没有实际包含一个对象,它只是引用一个对象(或者没有引用任何对象null),任何对象变量的值都是对存储在另外一个地方的某个对象的引用。

     LocalDate.now(),LocalDateTime.now()

       使用this关键字可以将实例字段和局部变量明显地区分开来(参数变量名会遮蔽同名的实例字段)。

       字段访问器方法,字段更改器方法。

       不要编写返回可变对象引用的访问器方法,因为会破坏封装性。如果需要返回一个可变对象引用,应该使用clone。

       由于公共数据非常危险,所以应该将所有的数据字段设置为私有的(final修饰就不一定需要是private,如公共常量)。

Java采用按值调用。方法参数类型有基本类型和对象引用两种。常见的例子就是交换两个对象变量的值是不能成功的(所以java不是按引用调用)。方法不能改变基本类型数据的值,但是可以改变对象参数的状态,方法不能让一个对象参数引用一个新的对象。

显示字段初始化会在执行构造器之前完成字段赋值操作。

调用构造器的步骤:(1)如果构造器方法调用了另外一个构造器方法,则执行另外一个构造器(使用this调用类的其他构造器方法)。(2)数据字段初始化为默认值(0,false,null).(3)按照在类中出现的顺序,执行字段的初始化方法和初始化代码块。(4)执行构造器主体代码。

包确保类名的唯一性,用于将类组织在一个集合中。在包中定位类是编译器的工作,类文件中的字节码总是使用完整的包名引用其他类。

无名包:java文件中没有package语句。无名包的类可以应用有名包的类,反过来不行。

类文件可以存储在JAR(Java归档)文件中,JAR文件使用ZIP格式组织文件和子目录。

super关键字的作用:使用super关键字调用超类方法,使用super调用超类构造器(如果子类的构造器没有显式调用父类构造器,则自动调用父类无参构造器)。

this关键字的作用:隐式参数的引用,调用类的其它构造器。

对象变量可以指示多种实际类型的现象称为多态,在运行时能够自动选择适当的方法称为动态绑定。

父类派生出子类,超类的私有方法不能通过super访问。

方法的名字和参数列表称为方法的签名,返回类型不是签名的一部分,在子类覆盖父类方法时,需要保证返回类型的兼容性,方法的可见性不能降低。

如果子类没有显式的调用超类的构造器,将自动调用超类的无参构造器,如果超类没有无参构造器,且子类没有显式地调用超类的其他构造器,编译会报错。这就是父类没有无参构造器,子类一定要定义构造器。

方法调用过程解析:1、虚拟机获取对象变量的实际类型的方法表。2、根据方法参数类型进行重载解析,选中方法。3、虚拟机调用方法。

final阻止继承类或者覆盖方法。

对象强制转换前,可以使用instanceof操作符判断是否可以成功转换。

进行强制类型转换的唯一原因:要在暂时忽略对象的实际类型之后,使用对象的全部功能。

包含一个或者多个抽象方法的类本身必须声明为抽象的(abstract),即使不包含抽象方法,也可以将类声明为抽象的。

子类不能访问父类的私有字段(可以通过访问父类提供的私有字段的public方法,super.方法()),对此可以方法或者字段声明为protected,这样子类可以直接访问这个字段。

protected方法代表子类和同一个包中的其他类都可见。

public:完全可见。 private:本类可见。 protected:本包和子类可见  默认:本包可见。

extends 派生自

 

 

Objects方法:

       equals:检测一个对象是否等于另外一个对象。

       hashCode:返回对象的散列码(一个int数字,包括正数和负数),默认从对象的存储地址中得出散列码。相等的对象返回相等的散列码。

       toString:返回表示该对象值的字符串(建议为自定义的每一个类都添加toString方法)。Ojbect定义的toStiirng方法打印对象的类名和散列码。

 

参数数量可变的方法(变参方法)。

枚举类不能构造新的对象,比较枚举类型的值使用==就行,构造器必须为私有,只是在构造枚举常量的时候调用,所有的枚举类都是Enum的子类,toString方法返回枚举常量名。比如Size s中s为Size.SMALL这种。