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字节整数。

常量在初始化后不可重新赋值。

image-20200415153749222

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

​ 在内部使用了数组来存储所有元素。

我们来比较一下ArrayListLinkedList

ArrayList LinkedList
获取指定元素 速度很快 需要从头开始查找元素
添加元素到末尾 速度很快 速度很快
在指定位置添加/删除 需要移动元素 不需要移动元素
内存占用 较大

通常情况下,我们总是优先使用ArrayList

Set

HashSet比较常用

1.请注意,此实现不同步。 如果多个线程并发访问哈希集,并且至少有一个线程修改该集合,那么它必须在外部进行同步。

2.如果我们只需要存储不重复的key,并不需要存储映射的value,那么就可以使用Set。3.Set用于存储不重复的元素集合,它主要提供以下几个方法:

​ 将元素添加进Set:boolean add(E e)

​ 将元素从Set删除:boolean remove(Object e)

​ 判断是否包含元素: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()方法可以等待其执行结束;

  1. 在线程中调用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 { private T[] array; private int size; public void add(T e) {...} public void remove(int index) {...} public T get(int index) {...} } 编译器看到泛型类型List就可以自动推断出后面的ArrayList的泛型类型必须是ArrayList,因此,可以把代码简写为: // 可以省略后面的Number,编译器可以自动推断泛型类型: List list = new ArrayList<>(); E是指方法接收的参数为任意类型

正则表达式

Paren 基本匹配1。\转义(转义特殊字符&,\等) .可以匹配一个任意字符 \d匹配数字 \D匹配非数字 \w可以匹配一个字母、数字或下划线 \s可以匹配一个空格字符(包括\t) 中文匹配2。a\u548cc匹配字符串"a和c" 中文字符和的Unicode编码是548c 重复匹配3.修饰符*可以匹配任意个字符 修饰符+可以匹配至少一个字符

jdk8新特性

jdk升级的原因:

​ 1提高效率

​ 2简化书写

​ 3提高安全性

1.lambda表达式 (简化书写)