一、基础
1.简介
- Java和C++都是静态类型的面向对象编程语言
- Java一律采用Unicode编码方式(字符集),每个字符无论中文还是英文字符都占用2个字节
- Java的class文件编码为UTF-8(编码规则),而虚拟机JVM编码为UTF-16
- Java中的char默认采用Unicode编码,所以Java中char占2个字节
- 程序
java.exe java虚拟机
javadoc.exe 用来制作java文档
jdb.exe java调试器
javaprof.exe 剖析工具
javac.exe 编译.java文件
2.标识符
标识符以字母、_或$开头
3.基本数据类型
- boolean默认值为false;占1个字节
- float类型必带f;如float a=1.5f;
- double必须带小数,变量除外;如double a=3.0,double b=5.3e12,Double b=t;(其中int t=3;)
- Interger比较大小
在范围[-128,127]为true,超过为false
例如:
Integer a=120;
Integer b=120;
则 a==b
- byte
所有的byte,short,char型的值将被提升为int型,除非操作的2个变量都用final修饰
示例:
byte b1=3, b2=4;
final b3=5, b4=6;
b1+b3(int型),b3+b4(byte型)
- 不同类型优先关系
byte,short,char-> int -> long -> float -> double
4.关键字
- 关键字全部都是小写
(1)final
final修饰变量,则等同于常量,不能再次被赋值
final修饰方法中的参数,称为最终参数。
final修饰类,则类不能被继承
final修饰方法,则方法不能被重写
(2)transient
- 将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化
4.条件
return
5.运算
(1)逻辑运算
&& 两者都要判断
|| 前者为true则后者无需判断
& 与 (1&1=1 1&0=0 0&0=0)
| 或 (1&1=1 1&0=1 0&0=0)
∧ 异或 (1&1=0 1&0=1 0&0=1) (相同为0不同为1)
如:14∧3=1110异或0011=1101=13
a++ 即a=a+1;
<< 左移位
>> 右移位
>>> 无符号右移
- Math.round(-11.5)=-11
- 三元操作符如果遇到可以转换为数字的类型,会做自动类型提升。如Object o1 = (false) ? new Double(1.0) : new Integer(2);得到2.0
6.异常
class Throwable implements Serializable
class Exception extends Throwable
class Error extends Throwable
return保存值,执行finally,最后返回已保存的值
try:
try-catch
try-finally
try-catch-finally
6.String
String s=new String("abc");
如果常量池中存在“abc”则不会创建,只创建1个new String("abc")的对象;
如果常量池中没有,则会创建2个对象。1个是对象的值“xyz”,1个是new String("abc")的对象
String s="welcome"+"to"+"java";
编译器编译时,直接把"welcome"、"to"和360这三个字面量进行"+"操作得到一个"welcometojava" 常量,并且直接将这个常量放入字符串池中,,这样做实际上是一种优化,将3个字面量合成一个,避免了创建多余的字符串对象(只有一个对象"welcometojava",在字符串常量池中)
public final class String implements Serializable, Comparable<String>, CharSequence
public final class StringBuilder extends AbstractStringBuilder implements Serializable, CharSequence
public final class StringBuffer extends AbstractStringBuilder implements Serializable, CharSequence
- 判断相等
String s1="abc";
String s2="abc";
String s3=new String("abc");
String s4="ab"+"c";
String s5="ab"+new String("c");
String s6=s3;
s1==s2 true
s2==s3 false
s1==s4 true
s1==s5 false
s3==s5 false
s3==s6 true
- 示例
String s1=“uml”;
String s2=“uml”;
String s3= new String (“uml”);
String s4= new String (“uml”);
分析:
s1==s2,比较的是比较的是地址和值,由上图得知两个引用指向的是同一个地址,所以返回 true.
s3==s4,比较的是两个new出来开辟的空间对象地址,所以值相同,但地址不同,返回 false.
s1.equals(s3),比较的是内容,返回true
7.数组
- 数组是一个对象,不同类型的数组具有不同的类
int[] a=new int[]{1,2,3};
int[] a=new int[100];
int a[]=new int[100];
- 2个数组用equals方法比较时,比较的是内存的地址
8.集合
class ArrayList<E> extends AbstractList<E> implements List<E>, Cloneable, Serializable
class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable
class Vector<E> extends AbstractList<E> implements List<E>, Cloneable, Serializable
interface Set<E> extends Collection<E>
class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
(1)HashMap
HashMap基于哈希表实现Map接口,允许null
使用链地址法解决hash冲突
非线程安全
(2)HashTable
HashTable禁止key或value为null
线程安全
(3)TreeMap
非线程安全
(4)ConCurrentHashMap
- ConCurrentHashMap禁止key或value为null
(5)List
- ArrayList是动态数组,增加空间时会复制全部数据到新大容量的数组中
- LinkedList是双向链表,按需分配空间
- Arraylist默认数组大小是10,扩容后的大小是扩容前的1.5倍,若新创建带初始值,默认就是传入的大小,也就不会扩容
9.参数传递
- 参数传递:地址传递、值传递
- 地址传递:String、数组、对象
- 值传递:基本数据类型,int,float、double等
引用传递只改变原变量的内容
值传递:
基本类型使用的是值传递类型,调用方法的时候在内存空间的栈中创建一个栈帧,每个栈帧里面保存当前变量的值;
当方法执行完成后,栈帧销毁,保存的变量的值也同时就没了,所以int类型的基本变量的值最后没有发生改变
引用类型:
非基本类型使用;
调用方法时候传参传递的是对象或者String或者数组的地址(这些对象都是保存在堆中,地址就是堆中相应的地址);
当改变发生的时候,地址是不会发生变化的,但是地址所对应的内容是可以发生改变的;
这就解释了为什么char数组中的字符发生了变化
String类型不可变:
String 类型是引用类型,那么为什么说不可变呢?
因为String类型比较特殊,String类型底层使用char类型的数组实现,但是由final修饰,因此不可变化。
String 类型的对象存在于jvm的字符串常量池中;
想要让String类型的字符串发生改变,就只能在字符串常量池中新建一个String类型的对象,然后将新的对象的地址指向变量。
这就解释了为什么String类型的变量没有发生改变
三、类和对象
(1)Object
hasCode() 返回该对象的哈希码值
equals() 判断某个其它对象是否与此对象相等
clone() 返回此对象的一个副本
toString() 返回该对象的字符串表示
finalize() 回收对象所占内存前调用,可临死挣扎一下
wait() 导致当前线程等待,直到其它线程调用此对象的notify或notifyAll方法
notify() 唤醒在此对象监视器上等待的单个线程
notifyAll() 唤醒在此对象监视器上等待的所有线程
(2)方法重载
同一个类中,允许存在1个以上的同名方法,只要参数个数或参数类型不同,与返回值类型无关
(3)方法重写
- 两同两小原则
存在于子类与父类之间,方法名相同,参数类型相同
子类方法返回类型小于等于父类方法返回类型
子类方法抛出异常小于等于父类方法抛出异常
子类方法访问权限大于等于父类方法访问权限
(4)执行顺序
1、父类静态代码块(可多个,顺序)
2、子类静态代码块
3、父类构造块(可多个,顺序)
4、父类构造函数
5、子类构造块(可多个,顺序)
6、子类构造函数
静态块:用static申明,JVM加载了诶时执行,仅执行一次
构造块:类中直接用{}定义,每一次创建对象时执行
执行顺序优先级:静态块 > main() > 构造块 > 构造函数
(提示)加载完类信息,再实例化
(5)超类即父类,super
(6)修饰符
- 修饰符
**访问权限修饰符:**
public:共有访问。对所有的类都可见
protected:保护型访问。对同一个包可见,对不同的包的子类可见
default:默认访问权限。只对同一个包可见,注意对不同的包的子类不可见
private:私有访问。只对同一个类可见,其余都不见
**非访问权限修饰符:**
static 修饰符,用来创建类方法和类变量
final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的
abstract 修饰符,用来创建抽象类和抽象方法
synchronized 用于多线程的同步
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。
而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值
transient:序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量
- 形参只能用final修饰
- 子类能继承父类所有成员,但对于private没有访问权限
- protected 修饰的成员变量被该类自身、与它在同一个包中的其它类、在其它包中的该类的子类所访问
(7)抽象类
- 抽象类可以有构造函数,但不能实例化
- 抽象类有抽象和非抽象方法,其中抽象方法不能有方法体
- is-a:继承关系;has-a:从属关系(接口);like-a:组合关系
- 需要抽象类:
1个类中有抽象方法则必须申明为抽象类;
抽象类中的抽象方法必须由其子类实现,若子类不能实现则子类也必须定义为抽象类
1个类实现1个接口就必须实现其中所有的抽象方法,若不能实现接口所有方法则该类定义为抽象类
(8)接口
- 接口无构造函数,不能实例化
- 成员变量必须public static final,无静态方法(jdk8允许),方法默认public abstract
- 接口可以多继承; interface D extends A,B,C
(9)静态与非静态
静态只能访问静态(变量和方法),非静态无限制
(10)访问权限
- public > protected > 默认(包访问权限) > private
(11)内部类
- 成员内部类可直接调用外部类的所有方法(静态方法及非静态方法)
- 局部内部类如同方法里的变量,没有public、private、static等修饰符
- 匿名内部类不具有类名,无构造函数,无抽象和静态属性,不能有访问修饰符不能派生出子类
- 使用示例
interface Product{
public double getAge();
public String getName();
}
public class Test {
public void print(Product p){
System.out.println(p.getName()+","+p.getAge());
}
public static void main(String[] args){
Test t=new Test();
//实现接口并实现抽象方法
t.print(new Product() {
@Override
public double getAge() { //实现方法
return 20;
}
@Override
public String getName() { //实现方法
return "Kangkang";
}
});
}
}
- 静态内部类不能直接访问外部类的非静态成员
(12)类关系
- “IS-A”、“HAS-A”、“USES-A” (是你、有你、用你)
(15)其它
getClass().getName(); 包名+类名
类与类之间只能单继承,但能多层继承
instanceof 判断前者是否可以类型可以转化为后者
四、线程
(1)setDaemon
- setDaemon需写在start之前
public final void setDaemon(boolean on) {
checkAccess();
//判断当前线程是否处于活动状态,若已运行抛异常
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
(2)volatile
volatile解决变量在多线程之间的可见性,有序性
轻量级,性能更好,只能修饰变量
(3)synchronized
synchronized解决多线程之间资源同步问题,保证原子性、可见性,有序性
多线程访问synchronized会发生阻塞
修饰方法、代码块
(4)join
等待该线程终止
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程
比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B
A.join(); //使调用线程A在此之前执行完毕。
A.join(1000); //等待A线程,等待时间是1000毫秒
(5)ThreadLocal
线程变量
ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的
ThreadLocal为变量在每个线程中都创建了一个副本,因此每个线程可以访问自己内部的副本数量
ThreadLocal存放的值是线程封闭的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递
ThreadLocalMap使用开放定址法解决hash冲突
(6)线程调度
线程调度分为协同式调度和抢占式调度;
java使用抢占式调度,即每个线程由操作系统分配执行时间,线程切换不是线程自身(协同式)决定的,这就是平台独立
sleep 是线程本身的静态方法,谁调用谁休眠(在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”)
join 调用后等待线程执行完成(等待调用join方法的线程结束,再继续执行)
synchroinized 修饰的方法和类,会让没抢到锁的线程停止执行
yield 让当前执行的线程让出cpu时间片,使当前线程重新回到就绪状态,不释放锁
wait 在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待
(7)其它
并发编程的同步器:
CountDownLatch 初始时给定一个值,每次调用countDown值减1,当值为0时阻塞的线程恢复执行
Semaphore 信号量。用于表示共享资源数量。用acquire()获取资源,用release()释放资源
CyclicBarrier 线程到达屏障后等待,当一组线程到达屏障后才一起恢复执行
Exchanger
使线程释放锁资源的操作:
wait()
join()
五、文件
1.字符流
- 字符流有缓冲流
2.字节流
- 字节流有缓冲流
六、序列化
序列化保存的是对象的状态
静态变量属于类,序列化不保存静态变量
七、socket
服务器端:
1、创建ServerSocket对象,绑定监听端口
2、通过accept()方法监听客户端请求
3、连接建立后,通过输入流读取客户端发送的请求信息
4、通过输出流向客户端发送响应信息
5、关闭响应的资源
客户端:
1、创建Socket对象,指明需要连接的服务器的地址和端口号
2、连接建立后,通过输出流向服务器发送请求信息
3、通过输入流获取服务器响应的信息
4、关闭相应资源
Socket s = new Socket(“192.168.1.1”,8080)
八、JVM虚拟机
1.java命令
- java
javac 编译java文件生成字节码文件
示例: javac Test.java 生成 Test.class
java 运行字节码文件
示例: java Test
2.创建对象
Java内存分为栈内存和堆内存
A a=new A();
在栈中创建变量a,在堆中创建对象new A(),变量a指向对象地址
3.反射
通过反射可以动态的实现一个接口,形成一个新的类,并可以用这个类创建对象,调用对象方法
通过反射,可以突破Java语言提供的对象成员、类成员的保护机制,访问一般方式不能访问的成员。只能访问,不能修改
Java的反射机制会给内存带来额外的开销。例如对永生堆的要求比不通过反射要求的更多
4.ClassLoader
java应用启动过程涉及3个ClassLoader:
Bootstrap
Extension
System
类装载器需要保证类装载过程的线程安全;
类加载器不加载接口;
双亲委派模式:
如果一个类加载器收到了类加载请求,它不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,所以默认是父装载
自定义类加载器实现 继承ClassLoader后重写了findClass方法加载指定路径上的class
5.equals
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
(1)判定传入的对象和当前对象是否为同一个对象,如果是就直接返回true.
(2)判定传入的对象是否为String类型,若不是则返回false;
(3)判定传入的String值长度与当前的String值长度是否相等,若不相等就返回false;
(4)循环对比两个字符串的char[]数组,逐个对比字符是否一致,若出现不同字符返回false;
(5)循环结束都没有出现不同字符,最后返回true;
例子:
String a="hello"; 放在常量池中
String b="hello"; 在常量池中寻找
6.私有共享
私有:
程序计数器: 指令
java虚拟机栈: 局部变量(基本数据类型变量、对象引用变量)、动态链接
本地方法栈: native方法
共享:
java堆: 对象实例、数组
方法区: 类信息、常量、静态变量
7.堆内存
- 堆内存:新生代(1/3)、老年代(2/3)
- 新生代:Eden区(8/10)、From survivor(1/10)、To Survivor(1/10)
8.垃圾回收
jvm中垃圾回收:scanvenge gc和full GC
full GC触发的条件:
老年代满、持久带满、System.gc()
- CMS
CMS的GC过程有6个阶段:
1.初次标记
2.并发标记
3.并发可中断预处理
4.最终重新标记
5.并发清理
6.并发重置
(4个并发;2个暂停其它应用程序,无用户线程参与)
9.其它
java在运行时才进行翻译指令
this()和super()都必须在构造函数第1行
不能在static方法中调用this或super
判断一块内存空间是否符合垃圾收集器收集的标准:
1. 给对象赋值为 null,以下没有调用过。
2. 给对象赋了新的值,重新分配了内存空间。
九、MySQL
- 驱动
Class.forName("com.mysql.jdbc.Driver");
com.mysql.jdbc.Driver MySQL驱动
oracle.jdbc.driver.OracleDriver oracle驱动
sun.jdbc.odbc.JdbcOdbcDriver Access驱动
- Statement
public interface PreparedStatement extends Statement
public interface CallableStatement extends PreparedStatement
- 关系数据模型
关系数据模型和对象数据模型之间对应关系:
表对应类
记录对应对象
表的字段对应类的属性
- Result
结果集Result从1开始遍历
十、正则表达式
- /D 匹配非数字
- \d 表示数字,等同于[0-9]
- ^ 起始符号
- $ 结束符号
- X{m} m 个X字符组成,\d{4}表4位数字
十一、Spring
- web容器负责将http请求转换为HttpServletRequest对象
- servlet
servlet周期包括 初始化、请求处理、销毁
- cookie
获取cookie的2种方式
访问方在header中加 Cookie="aa=bb;dd=ee"
request.getHeader("cookie")
Cookie[] cookies=request.getCookies();
十二、设计模式
- 单例模式
2个基本要点:
构造函数私有
唯一实例