这里的跨平台指的是跨操作系统平台。
Java通过不同的JVM将代码编译为在对应平台上可运行的文件。
重载发生在同一个类中,方法名相同,参数不同,类型不同或数量不同,且与返回值无关。
重写发生在父子类之间,为子类中出现了和父类中一样的方法声明,会对父类方法进行覆盖。
注意:重写方法访问权限不能比父类方法更低。
重写可以用@Override注解标明
Application Programming Interface 应用程序接口
对象如果想比较内容是否相同需要使用equals方法。
StringBuilder是一个可变的字符串类,可以看作一个容器,内容可变,不会作为常量存在常量池当中。
子类会自动拥有父类的所有属性和方法。并且可以自行添加特殊的属性和方法。
父类也称基类或超类。子类也称派生类。
this关键字访问本类内容,super关键字访问父类内容。
同一个对象,在不同时刻表现出的不同形态。
分具体类多态,抽象类多态,接口多态。
多态中方法,编译和成员变量访问要看左边引用的声明,但是调用方法要看子类的重写。
多态可以让我们传递父类引用,但是调用子类方法,简化代码编写,提高程序扩展性。但是不能够使用子类特有的功能。
abstract
没有方法体的方法为抽象方法
,带有抽象方法的类为抽象类
。
interface - implements
一种公共的规范。
接口中的成员变量默认是final和static的。
内部类是在一个类中定义另一个类。可以直接访问外部类的属性和方法。
外部类需要实例化内部类才能访问。
toString方法默认返回包名+@+哈希值
建议每个子类都重写该方法。
默认比较两个对象的地址值,与==
等价。
将基本类型封装成对象便于定义更多方法操作数据。
常用操作: 用于基本数据类型和字符串之间的转换。
valueOf
方法)xxValue
方法)equals
方法的时候,传入基本数据类型,会自动装箱为包装类,然后比较其中的值。由于equals
方法中会比较对象类型是否相同,因此如果传入不同包装类,即使值相同,也会返回false
。==
比较时,包装类会触发拆箱,同种类型比较时,会自动拆装箱。所有异常的超类是Throwable。
使用try-catch自定义处理异常时,如果在try块内出现异常,则会生成异常对象,然后递交JVM进行处理。JVM会检索catch块,寻找能够捕获的异常。
Collection:单列集合
Map:双列集合
List常用的两种实现类:ArrayList和LinkList,在底层数据结构上有区别,一个是可变大小的数组,一个是链表。
Set
HashSet底层使用Map实现的,实际上是HashMap的一个实例。其中元素的唯一性通过在插入时分析对象的哈希值(根据元素的hascode值计算得到)以及equals方法,判断是否插入。因此如果用HashSet保存对象元素,必须重写hashCode和equals方法。
HashSet的元素访问顺序是随机的,或者说与哈希函数有关。
LinkedHashSet使用哈希表和链表实现,迭代顺序与插入顺序一致,链表保证元素有序,哈希表保证元素唯一。
TreeSet能够使元素默认按照自然排序顺序迭代。也可以传递一个自定义比较器进行自定排序。
哈希表 HashMap
JDK1.8之前底层使用数组+链表
实现,使用拉链法做哈希函数的冲突处理。
JDK1.8之后做了优化,在链表长度超过一定阈值(8)之后使用红黑树(treeMap)替代链表作为底层数据结构实现,保证查找效率。
当填充比(加载因子)超过一定阈值(默认为0.75)时,会对数组进行扩容,扩大到原来的两倍,进行再散列,这样能够缩短链表长度,增大查找效率。
泛型
两种方法:
继承Thread,重写run方法。run方法封装执行代码,通过start方法启动线程,由JVM调用线程的run方法。
实现Runnable接口,重写run方法,以Thread类构造方法的参数传入进行运行。
可以避免Java单继承的局限性。
数据安全问题:多线程环境,有共享数据,是否有多条语句操作共享数据。
线程安全就是看有没有加synchronized关键字,是不是同步操作。
StringBuffer、Vector、HashTable、ConcurrentHashMap(高并发,安全度高)
对于线程不安全的类,可以通过Collections中的synchronized方法将其转变为线程安全。
为了更清晰的表达如何加锁和释放锁。比synchronized有更多的锁类型,有更广泛的锁定操作。
ReentrantLock:可重入锁/排他锁
和synchronized类似,必须等待一个线程代码块执行完毕其他线程才能执行。
ReadWriteLock:读写锁接口
将读写操作分开。具体实现类有ReentrantReadWriteLock。
函数式编程思想:尽量忽略面向对象的复杂语法,强调做什么,而不是以什么形式去做。
//使用lamda表达式方式启动一个线程
new Thread(()->{
//任务
}).start();
标准格式为:(形参)->{代码块}
()
也可以省略{}
和;
。如果有return
,return
也要省略。匿名内部类可以实现任何种类的类:具体类,抽象类,接口。
Lamda表达式实现方法必须是一个接口。
匿名内部类可以重写多个方法,Lamda表达式只能对应其中一个方法。
两者实现方式不同:
使用已存在的方案(Lamda表达式的一种替代形式)。
会自动将参数传递给方法。
有且仅有一个抽象方法的接口。适用于lamda表达式的接口。
使用注解@FunctionalInterface
表明其为函数式接口(可选)。
如果传递参数或返回值是一个函数式接口,我们可以以Lamda表达式形式表示。
Java8之后加入默认方法和静态方法
Java9之后加入了私有方法
default关键字修饰方法:解决接口升级问题,不破坏现有接口实现。
static关键字修饰:只能被接口调用,不会被实现类继承。
private关键字修饰:实现私有共有代码,不让外部类调用。为默认方法和静态方法提供服务。
简化Collection操作。
通常结合Lamda表达式使用,其中传递函数式接口。
使用方法:
生成流:通过数据源(集合/数组等)例:list.stream()
of(T... values)
中间操作:打开流,做出某种过滤或映射,然后生成新的流给下一个操作使用
终结操作:对流进行最后的操作。
收集操作:collect操作,传递参数,映射为不同类型的Collection
传递Collectors.xxx
对未加载到内存中的类,JVM会进行类加载、类链接、类初始化完成类的初始化。
不出意外,JVM会连续完成三个步骤,所以有时吧三个步骤统称为类加载货类初始化。
java.lang.Class
对象在运行时获取一个类的变量和方法信息,然后通过获取到的信息来创建对象,调用方法。是一种动态操作,增强了程序的灵活性,使程序运行期间仍可以扩展。
要通过反射使用一个类,首先要获取该类的字节码文件对象,也就是Class类型的对象。
获取Class对象的方式:
反射可以用于越过范型检查,通过调用成员方法时传递父类Class对象实现。
反射也可以用于读取配置文件,动态的配置服务。
Java9完善了模块化的概念,使得Java能够更小型,更轻便的运行。并且能够分部分隐藏内容。
使用文件module-info.java
文件配置模块化,使用exports导出模块,使用requires依赖模块。
要定义一个服务接口,最后导出这个接口的一个实现类。
在模块配置文件中使用provide…with提供服务,use使用服务。
提供服务方对外提供接口,use使用服务提供的接口。