设计目标:Java~采用面向对象的方式,开发健壮的代码,花费最少的时间和减少困难。
基本要素
1.Java语言特点
面向对象:分析事物,将其抽象为一类包含相同特性(属性)、行为(功能)的对象集合。
编译&解释共存:Java源程序先被编译为字节码,再由JVM虚拟机将字节码解释成机器码。
平台无关性:Java程序由Java虚拟机实现其平台无关性。
多线程、稳健、安全可靠……
2.三大构件
JDK:Java开发环境,提供了Java工具和基本Java类库
JRE:Java运行环境,包含JVM标准实现和Java核心类库
JVM:Java虚拟机,用于解释字节码文件
语法基础
1.基本语法
2.基本类型&包装类型
基本数据类型
数据类型 | 字节 | 位数 |
---|---|---|
byte(字节) | 1 | 8 |
short(短整型) | 2 | 16 |
int(整形) | 4 | 32 |
long(长整形) | 8 | 64 |
char(字符型) | 2 | 16 |
float(单精度浮点型) | 4 | 32 |
double(双精度浮点型) | 8 | 64 |
boolean(布尔型) | 1 |
包装类型
包装类型是将基本数据类型转化为引用类型(对象实例)。
类型:Byte、Short、Integer、Long、Float、Double、Character、Boolean
包装类型缓存机制
Byte、Short、Integer、Long这4中类型都创建了[-128, 127]数值缓存;
Character创建了[0, 127]数值缓存;
Boolean提供了True、False。
注:当基本类型转化为引用类型后,如何超出数值范围,则需要创建新的对象。
基本类型&包装类型区别
初始化:基本类型初始化默认值不为null、包装类型不赋值则初始化为null
空间存储:包装类型属于对象,存在于堆内存中;未被static修饰的成员变量基本类型存在于堆中。
空间占用:基本类型占用空间小
泛型适用:包装类型可以用于泛型
自动装箱&拆箱
自动装箱:将基本类型包装成引用类型;
自动拆箱:将包装的引用类型拆解成基本类型;
Integer i = 10; // 装箱
int n = i; // 拆箱
3.类的访问修饰符
修饰符 | 当前类 | 同包 | 子类 | 其他包 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y | |
default | Y | Y | ||
private | Y |
面向对象
1.类
类:包含一类对象的特性、行为,是对象的蓝图。类是一种数据类型。只存在于.class文件中。
成员变量&局部变量:
语法形式:
成员变量存在于类中。局部变量存在于代码块、方法中。
局部变量只能被final修饰。成员变量修饰范围更广泛。
存储方式:
成员变量被static修饰,则属于类。未被static修饰,则属于对象,存储于堆内存中。
局部变量存储于栈内存中。
生命周期:
成员变量属于对象,生命周期和对象一致。
局部变量存在于方法栈中,生命周期和方法一致。
初始值:
成员变量不赋值时,则通常采用各自的默认值初始化。如果被final修饰,则必须显示初始化赋值。
局部变量则不会自动赋值。
2.构造器
Java中类的构造器主要用于确保类在调用之前能够初始化,提高了Java编程中的安全性。
3.方法重载&方法重写
方法重载:方法重载作用于同类中,只与方法中的参数个数、类型、顺序有关,与其他无关。构造器是一种特殊的方法重载。方法重载使用Overload修饰。
方法重写:方法重写作用于父子继承关系中,通常用于子类对父类已有的方法进行自身的改造。方法重写使用Override修饰
4.this&static&final
this:代表调用者对象自身,通常存储与堆内存中的对象中,是一个对自身的引用。
static:用于区分成员是属于类,还是属于对象实例。编译期直接进行内存的初始化分配,且只占用一份存储空间。对于一些没有必要初始化的类、特性、行为等,则推荐使用static关键字来进行标识。
final:标识于类、属性、方法。常量、且不可继承。private方法中隐式的指定为final。
5.三大特征
封装:隐藏具体的实现细节,只对外提供可访问的接口。安全性。
注意点:
1.Java中单继承,且所有类都间接的继承自Object类。
2.private方法中通常隐式的指定了final。
3.子类可以拥有基类的特性、行为;基类中的私有方法只能拥有,无法访问。构造器无法继承,通过supper()调用基类构造。
4.子类构造初始化之前,会先初始化基类的构造器。
继承:抽离出多个类中共享的特性、行为来构造成一个共用的父类。复用性。
多态:同一类对象的多种实现方式。
子类赋值给父类引用时,则发生向上转型;将父类强制转换为子类对象,则发生向下转型。
静态方法、构造器不存在多态(构造器中隐式的声明了static,子类初始化调用时,则会首先向上链接初始化加载父类构造)。
6.接口
1.抽象类&抽象方法
界定:包含抽象方法的类叫做抽象类,用abstract修饰。(包含抽象方法时,必须声明为抽象类,否则编译报错)。抽象类是介于接口和子类之间的一个非完全抽象类。
抽象方法:方法声明是一样的,但是不同的子类中具有不同的实现。
注意点:
抽象类中可以包含非抽象方法(提供方法实现),当所有子类都需要实现相同的方法,且方法体一样;并且还可实现自己特有的方法时,推荐使用abstract父类进行抽象。
将都需要实现的fly()方法定义为非抽象方法并进行实现;
将eat()方法定义为abstract抽象的,让其子类自己实现。
2.接口
界定:接口是一种完全抽象的抽象类,其中的方法均为抽象声明,不提供具体的实现。用interface修饰。
接口域:接口中的域都是static、final的。且必须进行一个初始化,不能存在空的final。
7.抽象类&接口差异
相同点:
都无法直接实例化;
都包含抽象方法;
都提供了默认方法实现。
不同点:
接口是完全抽象的,重在提倡类的行为约束;抽象类是一种非完全抽象的,重在提倡代码的复用性。
接口中的域均为public static final,且必须初始化赋值;抽象类中的域为default、不必初始化赋值,子类可重新定义与赋值。
8.内部类
界定:定义在类中的类叫做“内部类”。
作用:将类的实现隐藏到所需的类中,是一种关联组织,并不等同于组合。了解外围类,并可与之通信。
类型:成员内部类(类中的成员变量)、 局部内部类(方法中定义)、静态内部类(static修饰,与外围类无 联系)、匿名内部类(定义内部类的同时提供类的实现)。
语法;
//常见用法
public class User{
//
class avator{
//内部类中的方法可以访问外部类的字段
}
}
访问:内部类访问外围类,使用外围类.this。外围类创建内部类,使用外围类.new 内部类();
//.this使用实例
public class User{
public class test{
public User print(){
return User.this;
}
}
}
//.new使用实例
public class User{
class test1{
private int i = 1;
public int value(){return i;}
}
class test2{
private int i = 2;
public int value(){return i;}
test2(int i){
this.i = i;
}
}
}
psvm{
User u = new User();
User.test1 t1 = u.new test1();
User.test2 t2 = u.new test2(4);
//伪代码
sout->t1.value();
sout->t2.value()
}
转型:当一个内部类向上转型为基类&接口时,获取到的引用其实是指向的基类&引用,方便隐藏实现细节。
public interface Destination{
String readLabel();
}
public interface Contents{
int value();
}
class Parcel4 {
private class PContents implements Contents {
private int i = 11;
@Override
public int value() { return i; }
}
protected final class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
@Override
public String readLabel() { return label; }
}
public Destination destination(String s) {
return new PDestination(s);
}
public Contents contents() {
return new PContents();
}
}
public class TestParcel {
public static void main(String[] args) {
Parcel4 p = new Parcel4();
Contents c = p.contents();
Destination d = p.destination("Tasmania");
// Illegal -- can't access private class:
//- Parcel4.PContents pc = p.new PContents();
}
}
异常
1.体系结构
1、Java中的异常、错误都继承自java.lang包下的Throwable类。
2、Throwable下提供Exception、Error两个子类。
3、Exception下提供Checked Exception、Unchecked Exception两种异常。
4、Checked Exception下又包含RunntimeException、IO、SQLException等。
2.Exception&Error
相同点:
两者都继承自java.lang包下的Throwable父类。
不同点:
Exception通常是程序自身可以进行处理的,可以抛出给上级调用者处理,获取直接捕获进行自身处理;
Error通常指的是程序无法处理的错误,更多的是JVM运行时内存不足等问题,这是会直接结束线程的运行。
3.必检异常&免检异常
CheckException:必检异常,不进行捕获或者抛出则无法编译通过。
UnCheckedException:免检异常,通常指的是RunntimeException及其子类(空指针、数组下标越界……)
4.Throwable常用方法
String getMessage() 获取简要信息
String toString() 获取详细信息
String getLocalizedMessage() 返回异常信息的本地化信息
void printStackTrace() 打印Throwable封装的异常信息
泛型&反射
1.泛型
界定:泛型是JDK5中提出的新特性,是一种对类型约束的限制解除,编译器进行泛型的安全转型。
类型:泛型类、泛型接口、泛型参数、泛型方法。
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey(){
return key;
}
}
// 泛型接口
public interface Generator<T> {
public T method();
}
// 泛型方法
public static < E > void printArray( E[] inputArray )
{
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
**泛型擦除:**<br />下面代码中,clazz1和clazz2起初一看是不同的类型,但实际上是相同的类型。
public class solution{
public static void main(String[] args){
Class clazz1 = new ArrayList<String>().getClass();
Class clazz2 = new ArrayList<Integer>().getClass();
class1 != class2;
}
}
这是因为,Java在**编译期间**会对泛型进行擦除。如果指定了边界,则会擦除到第一个边界,无边界,则擦除到Object。<br />**边界:**<br />参数泛型化的适用范围,指明泛型表示的类型范围。<br />**通配符:**<br />无界通配符:<?><br />上界通配符:<? extends T>。表示只能存放父类、及其父类的派生类。<br />![](https://cdn.nlark.com/yuque/0/2022/webp/27397677/1653895994482-12e50c8d-baac-4c78-902b-83d0f57a5955.webp#clientId=u85a0d0c9-6fcc-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=udc17364c&margin=%5Bobject%20Object%5D&originHeight=349&originWidth=720&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=ud68a4b7a-130f-4638-87b8-1bd2aae98df&title=)<br />下界通配符:<? supper T>。表示只能存放父类、及其父类的父类。<br />![](https://cdn.nlark.com/yuque/0/2022/webp/27397677/1653896098452-d4ed3e5f-0fee-4ca9-885f-e81ad3ece2e2.webp#clientId=u85a0d0c9-6fcc-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=udf0de37e&margin=%5Bobject%20Object%5D&originHeight=370&originWidth=720&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u5b24808f-59ac-4ea1-8096-9cb8c5762de&title=)
2.RTTI&反射
界定:RTTI(运行时类型识别)、反射都是可以在编译期获取类型信息的方式,RTTI更加传统一些。
Class对象:每一个类都对应一个Class对象,包含类的所有信息。通常在使用的时候才进行加载。
特点:
反射可以使得编码更加灵活多变。
但是一定程度上也增加了不安全性。
3.三种获取方式
Class.forName("类的全限定名");
obj.getClass();
类名.class;
常见类
1.Object
Object是所有类的基类、其中提供了hashCode()、equals()等方法。
/**
* native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。
*/
public native int hashCode()
/**
* 用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。
*/
public boolean equals(Object obj)
/**
* naitive 方法,用于创建并返回当前对象的一份拷贝。
*/
protected native Object clone() throws CloneNotSupportedException
/**
* 返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。
*/
public String toString()
/**
* native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
*/
public final native void notify()
/**
* native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
*/
public final native void notifyAll()
/**
* native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。
*/
public final native void wait(long timeout) throws InterruptedException
/**
* 多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。。
*/
public final void wait(long timeout, int nanos) throws InterruptedException
/**
* 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
*/
public final void wait() throws InterruptedException
2.String
1.String为何不可变?
1.String类本身被final修饰、防止了该类被继承而进行破坏;
2.String类中的字符数组也被final修饰,且私有化。阻止了对外暴露且进行修改。
被final修饰的类不能被继承、修饰的方法不能被重写、修饰的变量不能进行重新定义赋值。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
2.String&StringBuilder&StringBuffer
可变性:String不可变;StringBuilder和StringBuffer均为可变字符串。
线程安全:StringBuffer线程安全,使用synchronized方法锁。
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public synchronized StringBuffer insert(int offset, char c) {
toStringCache = null;
super.insert(offset, c);
return this;
}
3.==&equals()
基本类型:
==比较的是值、equals()无法进行判断
引用类型:
==比较的是对象内存地址,equals()比较的是对象地址,重写后比较的是对象的值。
4.equals()
Object中的equals()未经过重写、比较的是对象的内存地址;
String中的equals()经过重写,比较的是对象的值。
5.hashCode()
hashCode()作用就是获取“散列码”,实际上是一个int类型的整数、确定对象在散列表中的索引位置。