java基础知识
JDK:编写java程序的程序员使用的软件
JRE:运行java程序的用户使用的软件,包含虚拟机,不包含编译器。为不需要编译器的用户提供的。
1. 三种字符串
String:字符串常量
StringBuffer:字符串变量(线程安全)
StringBuilder:字符串变量(非线程安全)
三种字符串的操作效率:StringBuilder > StringBuffer > String
(1) String:字符串常量
操作String相当于重新new一个对象,还可能涉及到垃圾回收,因此最慢
(2) StringBuffer和StringBuilder
a. 二者都是继承AbstractStringBuilder
b. 对二者的变量进行操作就是直接对该对象进行更改,而不进行new和回收的操作,所以速度比String快很多。
c. 二者主要区别在于StringBuffer是线程安全的,StringBuilder是非线程安全的。StringBuffer大部分方法都是被synchronized关键字修饰,为了保证多线程同步,一些线程可能遇到阻塞的情况,这就使得Stringbuffer的运行时间增加,故StringBuffer效率略低于StringBuilder。
(3) 使用总结
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用于多线程下在字符缓冲区进行大量操作的情况
(4) 字符串常量的拼接(快)
(5) 字符串+字符串变量、字符串变量之间的拼接(慢)
(6) 使用以数组为底层数据结构的类型时,最好要预估大小
例如:StringBuilder底层数据结构就是一个字符数组value[],该数组默认大小为16,当超出这个大小时,会重新分配内存进行扩容(原大小的2倍+2),然后将原来数组的内容拷贝到新的数组,原数组被丢弃,这个过程非常消耗资源,要尽量避免这种操作。
2. synchronized关键字
synchronized是java中的关键字,是一种同步锁。它修饰的对象有以下几种:
(1) 修饰一个代码块:被修饰的代码块称为同步语句块,其作用范围是大括号{}括起来的代码,作用对象是调用这个代码块的对象。
(2) 修饰一个方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象
(3) 修饰一个静态方法:其作用的范围是整个静态方法,作用的对象是这个类的所有对象
(4) 修饰一个类:其作用范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象
a. 无论synchronized关键字加在方法上还是对象上,如果他作用的对象是非静态的,则取得的锁是对象;如果synchronized作用的对象是一个静态方法或者一个类,则它取得的锁是类,该类所有的对象同一把锁。
b. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码
c. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
3. 传参
(1) 基本数据类型
举例:int num = 10;
(2) 引用类型
举例:String str = "Hello";
(3) 什么是传值?
参数的值的拷贝
(4) 什么是传引用?
参数的地址
对于引用类型的变量,要清楚三个概念:
a. 变量的值
b. 变量的地址
c. 变量所引用的对象的地址
(5) java是传值还是传引用?
java只有传值,没有传引用,参数传递本质上就是复制的过程
(6) 基本数据类型的赋值
举例:int num = 10;
int num1 = num;
num1 = 20;
(7) 基本数据类型的传参
方法不能改变基本数据类型的参数
(8) 引用类型的赋值
举例:A a1 = new A();
A a2 = a1;
(9) 引用类型的传参
方法可以修改外部对象(实参)的属性,方法不能让外部对象引用一个新对象
(10) 引用类型的赋值之String
举例:String str = "Hello";
String str1 = str;
str1 = "World";
(11) 引用类型的传参之String
String是不可变类型,没有提供改变value[]值的方法
4. 继承
子类可以继承父类的哪些属性和方法
(1) public/protected修饰的
(2) 同一个包内,friendly修饰的
子类无法继承父类的哪些属性和方法
(1) 构造方法
(2) private修饰的
(3) 不同包内friendly修饰的
构造函数可以被继承吗?
(1) 不会被继承,只会被调用
(2) 创建有参构造函数后,系统就不再有无参构造函数,如果没有任何构造函数,系统会默认有一个无参构造函数
(3) 构造函数第一句一定是调用父类的构造函数,如果不显式调用父类有参构造函数,系统会默认调用父类的无参构造函数super();如果父类没有无参构造函数,又没有显式的调用有参构造函数-->报错。
5. 多态
父类引用指向子类对象
(1) 若子类重写了某方法,则父类引用调用子类重新定义的新方法
(2) 若子类未重写某方法,则父类引用调用父类本身的旧方法
(3) 若子类隐藏了父类的成员变量,则父类引用会访问到父类被隐藏的成员变量
(4) 若子类未隐藏父类的成员变量,则父类引用调用父类本身的成员变量
(5) 父类引用不能访问子类新定义的方法(如果想访问,需要强制类型转换)
子类引用指向自身对象
(1) 若子类重写了某方法,则子类引用调用子类重写的新方法
(2) 若子类未重写某方法,则子类引用调用父类本身的旧方法
(3) 若子类隐藏了父类的成员变量,则子类引用调用子类重新定义的新成员变量
(4) 若子类未隐藏父类成员变量,则子类引用调用父类本身的旧成员变量
(5) 子类引用可以访问子类新定义的方法
多态的必要条件
(1) 继承
(2) 重写
(3) 父类引用指向子类对象
使用父类引用指向子类对象时,该引用只能访问父类的方法和变量,如果子类重写了父类的方法,则会动态调用子类中的方法。(子类无法重写父类中的变量,只能使父类中的变量被隐藏)
不会重写成员变量,而是隐藏成员变量
(1) 在一个类中,子类中的成员变量如果和父类中的成员变量同名,那么即使他们类型不一样,父类中的成员变量都会被隐藏。
(2) 在子类中,父类的成员变量不能被简单的用引用来访问,而是,必须从父类的引用获得父类被隐藏的成员变量。
访问被隐藏的成员变量:使用父类的引用即可访问(强制类型转化)
6. 抽象类和接口
(1) 抽象类描述的是对象整体,包括属性和行为;接口一般描述某些行为
(2) 抽象类适合用来定义某个领域的固有属性,也就是本质,接口适合用来定义某个领域的扩展功能
(3) 如果需要多继承,只能用接口
(4) 如果有一些公用的方法实现,而且这些公用方法随时可能改变,则使用抽象类
(5) 当注重代码的扩展性和维护性时,应当优先采用接口。接口与实现它的类之间可以不存在任何层级关系,接口可以实现毫不相关类的相同行为,比抽象类的使用更加的方便灵活;接口只关心对象之间的交互的方法,而不关心对象所对应的具体类。接口是程序之间的一个协议,比抽象类的使用更安全、清晰。一般使用接口的情况更多。
7. final关键字
基本用法:
(1) 修饰类:当用final修饰一个类时,表明这个类不能被继承
(2) 修饰方法:使用final方法的原因有两个
a. 把方法锁定,以防任何继承类修改它的含义(父类的final方法不能被子类覆盖,不能被重写,可以重载多个final修饰的方法)
b. 效率。
(3) 修饰变量:对于一个final变量,如果是基本数据类型的变量,则其数据一旦在初始化之后便不能修改,如果是引用类型的变量,则在对其初始化之后便不能再让其指向另外一个对象。
final修饰一个成员变量(属性),必须要显示初始化,有两种初始化方式:一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有构造函数中对这个变量赋初值。
public class FinalTest{
private final int i = 0;
private Object obj;
public FinalTest(){
i = 1; //错误
final Object obj2 = new Object();
obj2 = new Object(); //错误
}
}
被final修饰的引用变量指向的对象内容可变吗?
答:引用虽然不能再指向其他对象,但是它指向的对象的内容是可变的
8. static关键字
static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。
方便在没有创建对象的情况下进行调用(方法/变量)
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
(1) static方法:
静态方法不依赖于任何对象就可以进行访问;静态方法中不能访问非静态成员方法和非静态成员变量,但是非静态成员方法中可以访问静态成员方法/变量。
(2) static变量
静态变量与非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
(3) static代码块
只会在加载的时候执行一次