java简介
java的历史
Java最早是由SUN公司(已被Oracle收购)的詹姆斯·高斯林(高司令,人称Java之父)在上个世纪90年代初开发的一种编程语言,最初被命名为Oak.1995正式更名为java
Java介于编译型语言和解释型语言之间。而Java是将代码编译成一种“字节码”,它类似于抽象的CPU指令,然后,针对不同平台编写虚拟机,不同平台的虚拟机负责加载字节码并执行,这样就实现了“一次编写,到处运行”的效果。当然,这是针对Java开发者而言。
对于虚拟机,需要为每个平台分别开发。为了保证不同平台、不同公司开发的虚拟机都能正确执行Java字节码,SUN公司制定了一系列的Java虚拟机规范。随着Java的发展,SUN给Java又分出了三个不同版本:
Java SE:Standard Edition Java EE:Enterprise Edition Java ME:Micro Edition
Java版本
从1995年发布1.0版本开始,到目前为止,最新的Java版本是Java 13:
| 时间 | 版本 |
|---|---|
| 1995 | 1.0 |
| 1998 | 1.2 |
| 2000 | 1.3 |
| 2002 | 1.4 |
| 2004 | 1.5 / 5.0 |
| 2005 | 1.6 / 6.0 |
| 2011 | 1.7 / 7.0 |
| 2014 | 1.8 / 8.0 |
| 2017/9 | 1.9 / 9.0 |
| 2018/3 | 10 |
| 2018/9 | 11 |
| 2019/3 | 12 |
| 2019/9 | 13 |
| 2020/3 | 14 |
java环境
简单地说,JRE就是运行Java字节码的虚拟机。如果只有Java源码,要编译成Java字节码,就需要JDK。
因为JDK除了包含JRE,还提供了编译器、调试器等开发工具。
java基础
命名
类名要求:以单词首个字母大写
方法:单词首个字母小写.
变量通常都是小写字母
长量通常都是大写字母。
变量和数据类型
基本数据类型是CPU可以直接进行运算的类型。(8种)
Java定义了以下几种基本数据类型:
整数类型:byte 1,short2,int4,long8
浮点数类型:float4,double8
字符类型:char2
布尔类型:boolean 理论上存储布尔类型只需要1 bit,但是通常JVM内部会把boolean表示为4字节整数。
常量在初始化后不可重新赋值。

main函数
1.public static void main(String[] args){ }
接收的是跟在javac 后面的参数
2.args==arguments
3.可以重载main函数,一个类也可以有多个main函数
不推荐这样写
jvm中的堆,栈,和方法区
堆:用来存放对象,数组
栈:用来存放方法,执行完后会释放资源,出栈
方法区:
静态方法区:用来存储静态资源,即静态变量,静态方法。
常量池:用来存放常量的。
面向对象编程
多态
多态的出现大大提高了程序的扩展性。不需要添加重复的代码。 前提:类与类之间有关系,要么继承,要么实现。 多态中子父类成员变量的特点:子类自动继承父类的变量,可进行复写。
多态成员函数的特点是:编译看左边,运行看右边。
成员变量和静态函数无论编译和运行都是看左边。
成员修饰符
1.public指所有类都能访问一个类只能有一个public修饰的类
2.private只有本类能访问 修饰后变量和方法都只能在本类访问
3.protected只有子类和子类的子类能访问
4.default只有本包能访问
5.只能修饰类的成员
this,super关键字
this是指当前对象的引用
super是父类对象的引用
this();是指调用当前对象的构造方法
super();调用父类的构造方法
static,内部类
static修饰的成员有静态变量(类变量),静态方法(类方法),静态代码块(类初始化代码块) 一般不定义静态,生命周期太长,而且清不掉三个特点
1.类的成员(静态变量和方法和代码块)总是优于实例成员加载(成员变量和方法)
2.静态代码块,静态变量只执行一次
3.静态变量加载进内存中的方法区,成员变量加载进堆内存, 静态变量是所有成员共享的。
静态内部类
1.内部类用静态修饰,可直接通过内部类名访问
2.方法中不能声明静态内部类
3.不能访问类中的非静态变量
匿名内部类
1.一般要继承一个类或接口,重写方法,也可以自定义方法,再调用
2.代码格式 new Runnerble(){ public void show(){ } }.show();
普通内部类
1.指一个类中再创建一个类,外部类要实例才内访问内部类,内部类可直接访问外部类。
2.内部类一般私有,然后再提供访问方法给外部,一般会加限制条件。
异常
java中的异常
Exception的异常 1.必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。 2.不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。
因为Java的异常是class,它的继承关系如下:
┌───────────┐
│ Object │
└───────────┘
▲
│
┌───────────┐
│ Throwable │
└───────────┘
▲
┌─────────┴─────────┐
│ │
┌───────────┐ ┌───────────┐
│ Error │ │ Exception │
└───────────┘ └───────────┘
▲ ▲
┌───────┘ ┌────┴──────────┐
│ │ │
┌─────────────────┐ ┌─────────────────┐┌───────────┐
│OutOfMemoryError │... │RuntimeException ││IOException│...
└─────────────────┘ └─────────────────┘└───────────┘
▲
┌───────────┴─────────────┐
│ │
┌─────────────────────┐ ┌─────────────────────────┐
│NullPointerException │ │IllegalArgumentException │...
└─────────────────────┘ └─────────────────────────┘
捕获异常
1.在catch里写异常处理逻辑,
e.getMessage() 输出 /by zero
e.toString 输出异常名称
e.printStackTrace 打印异常栈的跟踪信息。
是jvm默认的异常处理机制。
2.可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。存在多个catch的时候,catch的顺序非常重要:子类必须写在前面,否则只抛出首个异常。
3.使用try ... catch ... finally时:finally语句保证了有无异常都会执行,它是可选的;
一个catch语句也可以匹配多个非继承关系的异常。
抛出异常
1.throws Exception //声明了该功能有可能会出现问题。
2.处理异常要么处理,要么也不管直接抛出给jvm
RuntimeException
当该异常发生,希望程序停止,而不是由调用者进行捕捉
因为捕捉后不会知道调用出现了什么异常。
自定义异常时,如果该异常发生后,无法进行运算,就让自定义异常继承RuntimeException。 特点:出现该异常,运算无法继续,所以无法被处理。
ArethmeticException NullPointerException
自定义异常
对特有异常自己进行封装,生成对象
1.
class FuShuException extends Exception{
FuShuException(String msg){super(msg);
}
}
2.自定义异常只能手动抛出 if(b<0){throw new FuShuException("出现了除数是负数的情况");} 一般情况下,函数内出现异常,函数上需要声明.
3.如果只出现异常名称,却没有异常信息,需要复写Exception的方法。
4.抛出异常时,尽量复用JDK已定义的异常类型;
java核心类
String
String
1.String是一个对象
2.字符串最大特点:一旦初始化不可改变,是一个常量==是比较地址值,equals比较的是常量值常用方法常见功能-获取和判断 charAt equals 转换 tostring转换成字符串 切割和替换 split 比较和去除空格 equals trim(建议使用stringbuilder,效率最重要)
Stringbuffer
初始化后可改变,是字符缓冲区,是一个容器
1.长度可变化,线程安全
2.可以操作多个数据类型,
3.最终会通过tostring方法完成字符串操作 存储,删除,获取,修改 CURD create update read delete主要方法:append insert tostring
StringBuilder jdk1.5
一个可变的字符序列。 此类提供与StringBuffer的API,但不保证同步。
包装类
作用:用于基本数据类型和字符串之间做转换
byte Byte short short int Integer long Long boolean Boolean float Float double Double char Character
基本数据类型转成字符串。
基本数据类型+""
基本数据类型.toString(基本数据类型值);
如:Integer.toString(34);//将34整数变成"34";
字符串转成基本数据类型。
xxx a = Xxx.parseXxx(String);
通用,parse是转换的意思 静态的
int a = Integer.parseInt("123");
double b = Double.parseDouble("12.23");
boolean b = Boolean.parseBoolean("true");
Integer i = new Integer("123");
int num = i.intValue();
自动插箱装箱 1.5 简化书写
Int eger x = 4;//自动装箱。//new Integer(4)
x = x + 2;进行自动拆箱。变成成了int类型。和2进行加法运算。
注:当数值在byte范围内容,对于新特性,如果该数值已经存在,则不会在开辟新的空间。
容器
概述
集合 集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类
Conlection 是 List、Set 和 Queue 的父接口
set
HashSet、为优化査询速度而设计的 Set。
TreeSet、是一个有序的 Set,这样就能从 Set 里面提取一个有序序列
list
ArrayList 能进行快速的随机访问,效率高而且实现了可变大小的数组
LinkedList 随机访问较慢,优化了顺序访问
queue
ArrayDueue 是一个基于数组实现的双端队列,按“先进先出”的方式操作集合元素
map key 和 value 都可以是任何引用类型的数据
HashMap 按哈希算法来存取键对象
TreeMap 可以对键对象进行排序
Collection
Java标准库自带的java.util包提供了集合类:Collection,它是除Map外所有其他集合类的根接口。
1.Java集合的设计有几个特点:
一是实现了接口和实现类相分离,例如,有序表的接口是List,具体的实现类有ArrayList,LinkedList等。
二是支持泛型,我们可以限制在一个集合中只能放入同一种数据类型的元素。
2.List还允许添加null.
迭代器
什么是迭代器呢?Java访问集合总是通过统一的方式——迭代器(Iterator)来实现通过Iterator遍历List永远是最高效的方式。通过容器的iterator()方法获取该内部类的对象。
Iterator it = l.iterator();//获取迭代器,用于取出集合中的元素。
while(it.hasNext()) {
sop(it.next());
}
Java的foreach循环本身就可以帮我们使用Iterator遍历。
格式:for(数据类型 变量名 : 被遍历的集合(Collection)或者数组){
}
对集合进行遍历(数组也行)
List
List是最基础的一种集合:它是一种有序链表
1.需要增删元素的有序列表,我们使用最多的是ArrayList
在内部使用了数组来存储所有元素。
我们来比较一下ArrayList和LinkedList:
| ArrayList | LinkedList | |
|---|---|---|
| 获取指定元素 | 速度很快 | 需要从头开始查找元素 |
| 添加元素到末尾 | 速度很快 | 速度很快 |
| 在指定位置添加/删除 | 需要移动元素 | 不需要移动元素 |
| 内存占用 | 少 | 较大 |
通常情况下,我们总是优先使用ArrayList。
Set
HashSet比较常用
1.请注意,此实现不同步。 如果多个线程并发访问哈希集,并且至少有一个线程修改该集合,那么它必须在外部进行同步。
2.如果我们只需要存储不重复的key,并不需要存储映射的value,那么就可以使用Set。3.Set用于存储不重复的元素集合,它主要提供以下几个方法:
将元素添加进Set
将元素从Set
判断是否包含元素:boolean contains(Object e)
Map
1.Map是一种映射表,可以通过key快速查找value。最常用的一种Map实现是HashMap。
2.Map中不存在重复的key,因为放入相同的key,只会把原有的key-value对应的value给替换掉。
IO
File
File 类是 java.io 包中唯一代表磁盘文件本身的对象,也就是说,如果希望在程序中操作文件和目录,则都可以通过 File 类来完成。
IO输入输出
所有输入流类都是 InputStream 抽象类(字节输入流)和 Reader 抽象类(字符输入流)的子类。 所有输出流类都是 OutputStream 抽象类(字节输出流)和 Writer 抽象类(字符输出流)的子类。
每个 Java 程序运行时都带有一个系统流,系统流对应的类为 java.lang.System。Sytem 类封装了 Java 程序运行时的 3 个系统流,分别通过 in、out 和 err 变量来引用。 变量的作用域为 public 和 static
尽管它们通常用于对控制台进行读取和写入字符,但是这些都是字节流。因为预定义流是没有引入字符流的 Java 原始规范的一部分,所以它们不是字符流而是字节流,但是在 Java 中可以将它们打包到基于字符的流中使用。
java字节流
包括 ByteArrayInputStream 类、ByteArrayOutputStream 类、FileInputStream 类和 FileOutputStream 类。
java字符流
尽管 Java 中字节流的功能十分强大,几乎可以直接或间接地处理任何类型的输入/输出操作,但利用它却不能直接操作 16 位的 Unicode 字符。这就要用到字符流。
java转换流
正常情况下,字节流可以对所有的数据进行操作,但是有些时候在处理一些文本时我们要用到字符流,比如,查看文本的中文时就是需要采用字符流更为方便。所以 Java IO 流中提供了两种用于将字节流转换为字符流的转换流。
多线程
简介
是什么? Java语言内置了多线程支持:一个Java程序实际上是一个JVM进程,JVM进程用一个主线程来执行main()方法,在main()方法内部,我们又可以启动多个线程。此外,JVM还有负责垃圾回收的其他工作线程等。
为什么? 多线程经常需要读写共享数据,并且需要同步。例如,播放电影时,就必须由一个线程播放视频,另一个线程播放音频,两个线程需要协调运行,否则画面和声音就不同步。因此,多线程编程的复杂度高,调试更困难。
Java多线程编程的特点又在于: 多线程模型是Java程序最基本的并发模型; 后续读写网络、数据库、Web开发等都依赖Java多线程模型.
创建线程以及线程状态
能执行指定的代码的多线程创建方式
1.继承并重写run方法
public class Main {
public static void main(String[] args) {
Thread t = new MyThread(); t.start(); // 启动新线程
}
}
class MyThread extends Thread {
public void run() {
System.out.println("start new thread!");
}
}
2.创建Thread实例时,传入一个Runnable实例(常用)
public class Main {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start(); // 启动新线程
}
}
class MyRunnable implements Runnable {
public void run() {
System.out.println("start new thread!");
}
}
上面两种实现的方式的区别是:
1.继承方式只能继承一个类Thread
2.继承: 线程代码存放在Thread子类run方法中 实现: 线程代码存放在接口的子类的run方法中
3.jdk8引入的lambda语法简写
public class Main {
public static void main(String[] args) {
Thread t = new Thread(() -> {System.out.println("start new thread!");}); t.start();// 启动新线程
}
}
线程信息及操作
线程的信息及操作 Thread.curentTread().getName() 获取当前线程名
操作 1.通过对另一个线程对象调用join()方法可以等待其执行结束;
- 在线程中调用Thread.sleep(),强迫当前线程暂停一段时间 3.可以对线程设定优先级,设定优先级的方法是: Thread.setPriority(int n) // 1~10, 默认值5 线程的状态 new:新创建的线程,尚未执行;
Runnable:运行中的线程,正在执行run()方法的Java代码;
Blocked:运行中的线程,因为某些操作被阻塞而挂起; Waiting:运行中的线程,因为某些操作在等待中; Timed Waiting:运行中的线程,因为执行sleep()方法正在计时等待;
Terminated:线程已终止,因为run()方法执行完毕。
线程之间的操作
1.中断线程 eg:假设从网络下载一个100M的文件,如果网速很慢,用户等得不耐烦,就可能在下载过程中点“取消”,这时,程序就需要中断下载线程的执行。 1.中断一个线程非常简单,只需要在其他线程中对目标线程调用interrupt()方法,目标线程需要反复检测自身状态是否是interrupted状态,如果是,就立刻结束运行。
2.另一个常用的中断线程的方法是设置标志位。我们通常会用一个running标志位来标识线程是否应该继续运行,在外部线程中,通过把HelloThread.running置为false,就可以让线程结束 2.守护线程 守护线程是指为其他线程服务的线程。在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出。
如何创建守护线程呢?方法和普通线程一样,只是在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程。 3.线程同步 如果多个线程同时读写共享变量,会出现数据不一致的问题。 synchronized保证了代码块在任意时刻最多只有一个线程能执行 如何使用synchronized:
1. 找出修改共享变量的线程代码块;
2. 选择一个共享实例作为锁;
3. 使用synchronized(lockObject) { ... }。
线程安全问题
是什么:cpu执行线程的不确定性导致安全问题(多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来运行,导致共享数据出错)
是否有安全问题:
1.哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中哪些语句操作共享数据解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他现场不可执行。
同步的前提:
1必须有两个或两个以上的线程
2必须多个线程使用同一个锁 必须保证同步中只能有一个线程在运行java提供了专业的解决方式:
线程同步代码块 火车上的卫生间问题
synchronized(对象){ 需要被同步的代码 (哪些代码在操作数据)}
这个对象叫做安全锁好处:解决多线程的安全问题坏处:多个线程需要判断锁,较为消耗资源,在允许范围内
死锁
死锁:同步中嵌套同步多写几个同步就死锁了能自己手写一个死锁程序,线程同步这一块就了解的差不多了。
同步函数
同步有两种表现形式:
1.同步代码块进行同步
2.synchronized修饰符修饰函数(更方便)同步函数都有一个所属对象引用,就是this。同步函数用的锁是this。静态同步函数静态同步函数使用的锁是class,因为静态方法也不可以 定义this.
线程间通信
多线程通讯: 其实就是多个线程在操作同一个资源, 但是操作的动作不同。
等待唤醒机制: 在资源加一个标记boolean, 加入wait()和notify()机制。
等待的线程放在线程池中,通常唤醒的是第一个wait()的线程,按顺序存放的。 notifyAll();唤醒所有线程。 注:必须有对象监视器即同步锁 锁.wait(); 锁.notify(); 因为在操作同步线程,都必须要标识他们所操作的锁 只有同一个锁的被等待线程,可以被同一个锁上的notify唤醒。 而锁可以是任意对象,可以被任意对象调用的方法定义在object中。
生产者消费者
当出现多个生产者消费者时,必须用while循环和notifyAll();
Synchonized例子
package mode;
class Res{
private String name;
private String sex;
boolean flag=false;
public synchronized void set(String name,String sex) {
if(flag)
try{this.wait();}catch(Exception e){}
this.name=name;
this.sex=sex;
this.notify();
}
public synchronized void out() {
if(!flag)
try{this.wait();}catch(Exception e){}
System.out.println(name+"........"+sex);
flag = false;
this.notify();
}
}
class Input implements Runnable{
private Res r;
Input(Res r){
this.r=r;
}
@Override
public void run() {
while(true) {
int x = 0;
while(true)
{
if(x==0)
r.set("mike","man");
else
r.set("丽丽","女女女女女");
x = (x+1)%2;
}
}
}
}
class Output implements Runnable{
private Res r;
Output(Res r){
this.r=r;
}
@Override
public void run() {
while(true) {
r.out();
}
}
// TODO Auto-generated method stub
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Res r = new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
Lock例子
package mode;
import java.util.concurrent.locks.*;
public class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
JDK1.5 中提供了多线程升级解决方案。
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁 进行获取。
该示例中,实现了本方只唤醒对方操作。
Lock:替代了Synchronized
lock
unlock
newCondition()
Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
*/
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//t1,t2
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
}
// t3 t4
public void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.set("+商品+");
}
catch (InterruptedException e)
{
}
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.out();
}
catch (InterruptedException e)
{
}
}
}
}
泛型
泛型
泛型就是编写模板代码来适应任意类型;泛型的好处是使用时不必对类型进行强制转换,它通过编译器对类型进行检查;
泛型的使用
T可以是任何class。这样一来,我们就实现了:编写一次模版,可以创建任意类型的ArrayList:
public class ArrayList
正则表达式
Paren 基本匹配1。\转义(转义特殊字符&,\等) .可以匹配一个任意字符 \d匹配数字 \D匹配非数字 \w可以匹配一个字母、数字或下划线 \s可以匹配一个空格字符(包括\t) 中文匹配2。a\u548cc匹配字符串"a和c" 中文字符和的Unicode编码是548c 重复匹配3.修饰符*可以匹配任意个字符 修饰符+可以匹配至少一个字符
jdk8新特性
jdk升级的原因:
1提高效率
2简化书写
3提高安全性
1.lambda表达式 (简化书写)