# java基础知识

java基础知识

用于学习和复习的知识点总结

进程

  1. 进程:
    一个任务就是一个进程
    狭义定义:进程就是一段程序的执行过程。
    广义定义:进程是一个具有一定独立能力的程序关于某个数据集合的一次运行活动。
    它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本分配单元,也是基本的执行 单元。
    简单的来讲进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域、数据区域和堆栈。第二进程是一个“执行中的程序”。程序是没有声明的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
    进程状态:进程有三个状态,就绪、运行和阻塞。
    程序:
    程序是指令和数据的有序集合。
    线程:
    线程的组成:代码+数据+CPU。
    线程的执行必须要有CPU,如果分配不到CPU时间片,线程永远也无法执行(CPU时间片由操作系统调度,程序员无法控制。)
    JVM内存:任何程序的执行都是对数据进行处理,java也不例外。所有的数据保存在JVM的内存中。
    JVM内存包括:堆空间、栈空间、代码空间等…
    堆空间:保存对象和实例变量和线程共享。
    栈空间:保存局部变量和线程独立。
    代码空间:保存代码。
    Java线程是堆空间共享、栈空间独立。
    当CPU时间片到期后,切换线程时,只需切换栈空间而不需要切换堆空间。
    每个线程创建的对象是可以共享的
    线程的切换操作系统控制,程序员无法控制。
    一个线程也是一个对象。
    一个进程中包含若干个线程。通常我们把进程作为分配资源的基本单位,把线程作为独立运算和独立调度的基本单位。
    在操作系统中并发的任务就是进程。
    进程中有很多任务,每个任务就是一个线程。
    为线程编写代码:
    方法1:创建Thread1 extends Thread{
    Public void run(){
    //线程执行的代码
    }
    }
    创建Thread1类的对象
    Thread t1=new Thread1();
    启动t1子线程:
    t1.start();
    覆盖的是run()方法,为什么不使用run()启动线程。而使用start()方法?
    线程对象也是对象,调用线程对象的run()方法就是一个普通的方法调用,并不会创建新的线程。
    Java规定对一个线程对象调用start()方法时,会通知JVM向操作系统申请创建一个新的线程并启动。
    方法2:创建Runnable接口的实现类,实现run()方法
    Class Thread2 implements Runnable{
    Public void run(){
    //线程执行的代码
    }
    }
    创建Thread2类的对象
    Thread t2=new Thread(new Thread2());
    t2.start();
    一个线程有四种基本状态
    初始状态—start()—就绪状态—获取CPU—运行状态—代码结束—终止状态
    线程对象都有一个SetPriority()方法,用来设置线程的优先级别。
    如果一个线程主动的调用了yieid()方法,则会立即进入就绪状态,等待调度。
    线程的阻塞状态:一个线程在运行状态时,需要从键盘获取一个数据,此时线程即使有CPU的使用权也无法继续执行,就会进入阻塞状态。
    一个线程进入阻塞状态的条件;
    等待数据;
    主动调用了sleep()方法
    Sleep()有两个重载的方法,可以设置线程的睡眠时间。睡眠中的线程会进 入阻塞状态,可以在设定的时间到达后自动唤醒,也可以由其他线程对其使用 interrupt()方法唤醒。
    主动调用了join()方法
    对另一个线程对象使用join()方法,可以让当前线程进入阻塞状态,并让对方线程进入运行状态。
    当对方线程进入终止状态后,当前线程才能继续执行。
    Join()方法就是把两个并行的线程,转变成串行运行。
    线程间不要互相调用join()方法
    退出阻塞状态的条件:
    等待数据的线程获得数据
    睡眠的线程唤醒
    调用了其他线程的join()方法,等待对方线程进入终止状态阻塞的线程不会被操作系统调度,此时其他线程可以进入运行状态,退出阻塞状态的线程会进入就绪状态等待操作系统调度。
    多线程:
    多线程编程就是在JVM中创建多个线程。
    在一个程序中,这些独立运行的程序片段叫做线程。多线程是为了同步完成多项任务。
    进程和线程的关系:
    在一个操作系统中可以并发的执行多个进程
    在一个进程中还可以并发的执行多个线程
    当多线程并发的访问临界资源时,如果破坏了原子操作,就会出现数据不一致的情况,
    解决的方法:
    把原子操作保护起来,不许被打断,要做就都做,要不就都不做。
    使用synchronized关键字可以把原子操作锁起来。
    synchronized的第一种用法:
    Synchronized(o){//o为临界资源
    //对对象o加锁的同步代码块
    }
    任何一个Java对象都有一个互斥锁标记,用来分配给线程的。
    可以不分配给线程
    可以分配给一个线程
    不可以同时分配给多个线程
    只有拿到对象的互斥锁标记的线程,才能执行对这个对象加锁的同步代码块。
    线程退出同步代码块后,会将互斥锁标记归还给对象,对象可以把锁重新分配给其他线 程。
    即使是不同的同步代码块,只要对同一个对象加锁,同一时间也只能有一个线程进入。
    所以说,同步代码块的本质锁不是代码,而是对象。
    Synchronized的第二种用法:
    作为方法的修饰符
    使用synchronized修饰的方法为同步方法
    同步方法相当于把方法中的所有代码放入一个对this加锁的同步代码块中。
    一个线程进入一个对象的同步方法需要拿到对象的互斥锁标记,但是进入这个对象的非同步方法不需要互斥锁标记。
    如果一个类所有方法都是同步方法,那么这个类就是线程安全的,线程安全的类的性能会受到影响。
    synchronized不能修饰构造方法。
    synchronized不能修饰抽象方法。
    Synchronized可以修饰静态方法。
    每一个对象都有一块空间,用来存放等待此对象互斥锁标记的线程,此空间称为锁池。
    如果一个线程即将进入一个对象的同步方法而无法拿到它的互斥锁标记,就会进入这个对象的锁池中。
    锁池中的线程处于锁池状态。
    线程间的通讯使用等待-通知的方式。
    每个对象都有一个等待队列,用来存放线程。
    如果一个线程调用了一个对象的wait()方法,就会释放其所有的互斥锁标记,然后进入这个对象的等待队列中。
    Wait()方法有三个重载的方法,1.可以设置进入等待队列的时间。
    2.如果一个线程调用了一个对象的notify()方法,会释放这个对象的等待队列中的一个线程。
    3.如果一个线程调用了一个对象的notifyAll()方法,就会释放这个对象的等待队列中的所有线程。
    Wait()、notify()、notifyAll()方法都是Object类的方法,所以每个对象都有这几个方法。
    注意:对一个对象调用wait()、notify()或者notifyAll()方法的语句必须放在对这个对象加锁的同步代码块中。
    一个线程对一个对象调用了wait()方法后,就会释放其所有的互斥锁标记,进入等待状态。进入等待状态的线程一定是在对某个对象加锁的同步代码块中。
    当其他线程释放一个对象的等待队列中的线程时,被释放的线程必须拿到对象的互斥锁标记才能继续运行,所以马上会进入这个对象的锁池中,进入锁池状态。

进程与线程的区别:
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其他进程产生影响,而线程只是一个进程中的不同执行路径。
线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间。
1、一个程序至少有一个进程,一个进程至少有一个线程。
2、线程的划分尺度小于进程,使得多线程程序的并发性高。
3、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4、多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。
优缺点:
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP(多核处理机)机器上运行,而进程则可以跨机器迁移。

线程的同步
线程间的堆空间共享,栈空间独立
线程间通信

文件:
Java程序运行时,处理的数据都保存在JVM内存中。Java程序结束了,JVM就关闭了,而内存中的数据就消失了。
如何记录程序的运行结果,以便以后再次运行相同的程序时能够不需要重复处理已处理过的数据? 可以把数据以文件为单位保存在外部存储器中。

一个文件也是一个对象
一个File类的对象可以代表硬盘上的一个文件或者一个文件夹。Java程序对File程序对File类对象的操作实际上就是对硬盘上的文件或者文件夹的操作。
File file=new File(“C:\test.dat”);(file 对象关联了一个文件)
如果文件不存在,可以使用:
CreateNewFile()方法在硬盘上创建一个文件
Mkdir()方法在硬盘上创建一个文件夹
File类提供了对文件操作的方法:
Delete() 删除文件
Exists() 判断文件是否存在
GetAbsoluteName() 获得绝对路径
GetName() 获得文件名
IsDirectory() 判断是否为文件夹
IsFile() 判断是否为文件
Length()获得文件长度
File[] file= file.listFiles();(如果没有访问权限制则会返回null;)
For(File f:files){

}
如何递归的遍历一个给定文件夹中的内容
Public void fileTraverse(File file){
System.out.println(file.getName());
If(file.isDirectory()){
For(File f:file.listFiles()){
fileTraverse(f);
}
}
}
如何递归的遍历一个给定文件夹中所有java文件?
listFilter()有三个重载方法,其中参数类型为FileFilter的方法可以实现文件过滤的功能。
FileFilter是一个接口,只声明了一个accept()方法,这个方法决定在获得文件和子文件夹时,是否能够把一个文件放入数组。
Class MyFile implements FileFilter{
Public boolean accept(File f){
Return f.getName().endsWith(“.java”)||f.isDirectory()
}
}
设计模式: 总结的程序套路就是设计模式
常见的设计模式;
缺省适配模式------接口和抽象类
不变模式-----String类和包装类
迭代器模式------集合
装饰模式------流
装饰模式:

Interface Weapon{
Void fire();
}
Class Gun implements Weapon{
Public void fire(){
System.out.println(“发射子弹”);
}
}
Abstract class Part implements Weapon{
Private Weapon weapon;
Public Part(Weapon weapon){
This.weapon=weapon;
}
Public Weapon getWeapon(){
Return this.weapon;
}
}
Class SPart extends Part{
Public SPart(Weapon weapon){
Super(weapon);
}
Public void fire(){
Super.getWeapon().fire();
System.out.println(“增加散弹效果”);
}
}
Class FPart extends Part{
Public FPart(Weapon weapon){
Super(weapon);
}
Public void fire(){
Super.getWeapon().fire();
System.out.println(“增加火球效果”);
}
}
class LPart extends Part {
public LPart( Weapon weapon ) {
super( weapon );
}
public void fire( ) {
super.getWeapon( ).fire( );
System.out.println( “增加激光效果” );
}
}
main( ) {
Weapon w = new LPart( new FPart(
new SPart( new Gun( ) ) ) );
w.fire( );
}

流:
什么是流?
流是数据传输的通道,无论JVM从外部输入还是把数据输出到外部,都需要使用流。
一个流也是一个对象。
Java中的流可以按照三种方式划分:
1.按照方向分:输入流和输出流
2.按照单位分:字节流和字符流
3.按照功能分:节点流和过滤流
Java中流的父类:
共同特征:都是抽象类
字节流 字符流
InputStream Reader 输入流
OutputStream Writer 输出流
所有对流的操作只需三个步骤:
1.创建流
2.写数据
3.关闭流
FileOutStream是一个输出字节节点流,可以向一个文件中以字节为单位写入数据。
如何创建一个FileOutStream类的对象?
FileOutputStream类提供了多个构造方法,创建对象时,必须指定目标文件以及是否以追加方式打开。(true为追加方式 默认为false)。
FileOutputStream fos1=new FileOutputStream(file);
FileOutputStream fos2=new FileOutputStream(file,true);
FileOutputStream fos3=new FileOutputStream(“c:\test.dat”);
FileOutputStream fos4 =new FileOutputStream(“c:\test.dat”, true );
追加方式不会覆盖原文件中的内容,可以向一个文件中数据末端继续写入数据。
非追加方式会重新创建一个文件,如果原文件已存在,则会删除原文件中的数据。.
FileOutputStream类提供了三个重载的write()方法:
Byte b=97;
Fos1.write(b);//写一个字节
Byte[]bytes={97,98,99,100,101};
Fos1.write(bytes);//依次写数组中所有字节
Fos1.write(bytes,1,3);//从下标为1开始写3个字节
如果希望多次写入数据,可以在不关闭流的情况下多次调用write()方法。
写文件结束,要及时关闭流,以便释放已占用的资源。
Fos1.close();
向文件中写数据的完整流程
FileOutputStream fos=new FileOutputStream(“c:\test.dat”);
Fos.write(97);
Fos.close();
FileInputStream是一个输入字节节点流,可以从一个文件中以字节为单位读取数据。
FileInputStream fis1=new FileInputStream(file);
FileInputStream fis2=new FileInputStream(“c:\test.dat”);
FileInputStream类提供了三个重载的read()方法:
Byte b=(byte)fis1.read(); 读一个字节并返回;
Byte[] bytes=new byte[10];
Fis1.read(bytes); 读满数组返回读取字节数
Fis1.read(bytes,1,3); 从数组下标为1的位置填充3个读出的字节,返回读取字节数。
如果希望多次读取数据,可以在不关闭流的情况下多次调用read()方法。
读文件结束,要及时关闭流,以便释放已占用的资源。
Fis1.close();
从文件中读数据的完整流程:
FileInputStream fis=new FileInputStream(“c:\test.dat”);
Byte b=(byte)fis.read();
Fis.close();
异常处理的流程:

FileOutputStream fos=null;
Try{
Fos=new FileOutputStream( “c:\test.dat”);
Fos.write(97);
}catch(Exception e){
}finally{
Try{
If(fos!=null){
Fos.close();
}
}catch(Exception e){}
}
字节流
所以对流的操作只需要三个步骤:
1.创建流
2.写数据/读数据
3.关闭流
如果要把一个long类型的数据写入一个文件,如何实现?
Long类型的变量占8个字节,如果使用FileOutputStream把一个long类型的数据写入文件,需要先把这个数据转换成byte数组。
如何把一个long类型的数据转换成byte数组?
Java提供了DataOutputStream和DataInputStream类,可以用来读取各种类型的数据。
DataOutputStream除了继承了父类三种字节的方法,还提供了写8种基本类型和String类型的数据。
DataInputStream除了继承了父类三种读字节的方法,还提供了读8种基本类型和String类型的方法。
创建流:
DataOutputStream是一个输出字节过滤流,自己无法写数据,只能给其他的流增加写多种类型数据的功能,所以在创建对象时需要另外一个流对象。
DataOutputStream dos=new DataOutputStream(new FileOutputStream(“”C:\1.txt));
装饰模式
写数据:
DataOutputStream提供了多种写数据的方法,如果希望写一个long类型的数据,可以使用writeLong()方法:
Long l = 12345678L;
Dos.writeLong(l);
关闭流:
只需要关闭最外层的流,所有被封装到内部的流对象会依次被关闭:
Dos.close();
DataInputStream类的使用方法类似。
其他过滤流的使用方法也类似。
Java提供了BufferedOutputStream和BufferedInputStream类,这也是一对字节过滤流,它们的作用是可以给其他的流增加缓存。
字节流是以字节为单位读文件的,当频繁的访问外部存储设备时,使用缓存可以极大的提高访问效率。
PrintStream:
既可以作节点流,也可以做过滤流。
同时具备FileOutputStream、BufferedOutputStream、DataOutputStream的功能。
没有和它一对的输入流。

字符流

FileReader和FileWrite是一对字符节点流,可以用来读写文件,每次传输一个字符,所有的用法和FileInputStream、FileOutputStream相同。
BufferedReader和BufferedWriter是一对字符过滤流,可以给其他的字符流增加输入或输出缓存,提高输入和输出的效率。
PrintWriter同时具备FileWeiter和BufferedWriter的功能,它既是节点流,也是过滤流,并且没有和它一对的输入流。
桥转换流:InputStreamReader和OutputStreamWriter
(已经拿到了一个字节流对象,如果想把它转换成字符流,应该怎么做?)
InputStreamReader和OutputStreamWriter是一对特殊功能的流。他们的父类分别是Reader和Writer,也就是说,它们是字符流。
创建这两个类的对象需要其他的流对象,也就是说,它们是过滤流。
这两个流的特殊之处在于,它们是字符流,但是需要一个字节流创建对象。
这两个流的作用是把一个字节流包装成字符流,在两种不同类型的流之间搭建了一座桥,所以也叫桥转换流。
使用BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“C:\test.dat”),”UTF-8”));

使用BufferedReader包装一个字节流:
BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(“C:\test.dat”),UTF-8));
序列化和克隆
序列化:把一个对象保存到文件中(与其说是把一个对象保存到文件中,不如说是把这个对象在内存中的数据通过输出字节流保存在一个二进制文件中)。
把一个对象写入流中的过程叫做序列化。
从流中读出一个对象的过程叫做反序列化。
要想把一个对象序列化,前提是这个对象能序列化,不是所有对象都能序列化和反序列化。
如果试图序列化一个无法序列化的对象,就会抛出异常。
如何让一个Student对象能够序列化,必须让这个对象所属的类实现Serializable接口。Serializable接口是一个标识接口,没有任何方法的声明。
序列化对象是有风险的,让一个类实现Serializable接口就是程序员主动承担序列化对象的风险。
Class Student implements Serializable{…}
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream( “c:\test.dat”));
Student stu =new Student(“zhangsan”,20);//序列化对象
Oos.writeObject(stu);
ObjectInputStream ois=new ObjectInputStream(new FileInputStream( “c:\test.dat”));
Student stu = (Student)ois.readObject();//反序列化对象

思考:把一个对象序列化到文件中,都会保存对象的哪些内容?
只会把对象的属性保存,对象的方法不会保存
思考:一个对象要能够序列化,属性必须满足什么要求?
属性必须也能序列化。
如果属性包含子属性,必须保证子属性能够序列化。
如果属性是一个集合,必须保证集合中的元素能够序列化。
如果希望某个属性不被序列化,可以使用transient修饰符修饰这个属性。 被修饰的属性成为临时属性,不会参与序列化。
Class Student implements Serializable{
Private transient int score;//临时属性不参与序列化
}
克隆:
只要一个类实现了Cloneable接口,并覆盖Object类的clone()方法,扩大访问权限修饰符,就能在内存中复制出一个相同的对象。
Cloneable接口也是一个标识接口。
克隆对象是有风险的,让一个类实现Cloneable接口就是程序员主动承担克隆对象的风险。
网络编程概述:
网络协议分为以下五个层次:
应用层:为应用软件提供数据传输服务
运输层:使用不同的协议传输数据,决定数据传输的协议
网络层:把数据分成包,决定每个数据包的目标ip地址
数据链路层:把数据分成包,决定数据帧传输的控制信息
物理层:把数据帧分解成字节流传输
运输层协议:
TCP(传输控制协议)
UDP(用户数据报协议)
使用TCP协议传输数据
使用UDP协议传输数据

一个IP地址也是一个对象
IP地址对象属于InetAddress类。
InetAddress类没有公开的构造方法,只能使用公开的静态方法获得对象:
getLocalhost():获得本机的IP地址对象
InetAddress对象常用方法:
getAddress():获得表示IP地址的字节数组
getHostName():获得表示主机名的String对象
getHOSTAddress():获得表示IP地址的String对象
TCP协议是一种面向连接的运输层协议,在每次传输数据之前,必须先创建连接,才能传输数据,数据传输结束后要断开连接。
使用TCP协议传输的数据是可靠的,如果数据传输失败,发送端会自动重新发送数据,保证接收端收到正确的数据。
使用TCP协议传输数据,主动发起连接请求的一方为客户端,被动等待连接请求的一方为服务器。
在java中,客户端和服务器使用Socket对象进行TCP连接。
客户端的实现:
创建Socket对象,访问服务器的IP地址和提供服务的端口
Socket socket =new Socket(“localhost”,8888);//localhost为服务器IP地址,8888为服务端口
客户端的实现:
使用socket对象的getInputStream()方法获得输入字节流
使用socket对象的getOutputStream()方法获得输出字节流
InputStream in=socket.getInputStream();
OutputStream out = socket.getOutputStream();
注意:
可以使用字节流的方法给获得的字节流增加功能或者读写数据
通过socket对象获得的字节流带缓存,输出结束后要调用flush()方法手动清空缓存
可以包装成字符流传送文本数据
客户端的实现:
断开连接时需要调用socket对象的close()方法关闭连接,此时会同时关闭输入流和输出流,关闭后不能再使用流读写数据,或者选择单独关闭输入流或者输出流。
socket.shutdownInput();
Socket.shutdownOutput();
Socket.close();
服务器的实现:
创建ServerSocket对象,指定服务监听的端口
调用server对象的accept()方法获得socket对象,此方法为阻塞方法,直到有客户端发起连接后才会创建socket对象
ServerSocket server= new ServerSocket(8888);
Socket socket=server.accept();
和客户端相同的方法使用socket对象,使用后关闭
关闭ServerSocket对象
Server.close();
存在的问题;
服务器端只能创建一个socket对象,只能和一个客户端连接。如果要和多个客户端连接,如何实现?
改进:
为每个连接创建一个独立的子线程,负责和客户端连接,主线程继续等待其他客户端连接。

模式:
工厂模式:
代理模式:
动态代理模式:
有什么好处?
(代码开发原则:只增不改)
1.代理对象可以对原对象起到保护作用。在修改代码时候,不用修改原对象代码,直接修改代理对象代码就行了,可以分清责任。
2.在原对象的基础上,我们在代理类中还可以添加附加功能。
动态代理代码实现

代理模式的结构:
单例模式:
概念:只有一个实例对象
核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常见的应用场景:
任务管理器
回收站
配置文件的类
网站计数器
应用程序的日志应用
数据库连接池的设计
操作系统的文件系统
Servlet
单例模式的优点:
1.由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留在内存的方式来解决。
2.单例模式可以在系统设置全局的访问点,优化共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
实现:要求构造方法私有
饿汉式:(线程安全,调用效率高。但是,不能延时加载。)
懒汉式:(线程安全,资源利用率高,并发调用效率不高。但是可以延时加载。)
静态内部类(线程安全,调用效率高,但是可以延时加载。)
1.外部类没有static属性,则不会像饿汉式那样立即加载对象。
2.只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。Instance是statice final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性。
3.兼备了并发高效调用和延时加载的优势!!
4.代码实现:
public class SingletonDome4 {
private static class SingletoClassInstance{
private static final SingletonDome4 instance =new SingletonDome4();
}
private SingletonDome4(){

}
public static SingletonDome4 getInstance(){
	return SingletoClassInstance.instance;
}

}

枚举单例(线程安全,调用效率高,不能延时加载。可以天然的防止反射和反序列化漏洞!)
如何选用合适的方式实现单例模式:
单例对象 占用资源少且不需要延时加载时:枚举单例优于饿汉式
单例对象 占用资源大且需要延时加载时:内部静态类优于懒汉式
标注(Annotation):
什么是标注:
标注是一种注释。
传统的注释是给程序员看的,标注是给编译器看的。
标注是JAVA中的一种类型(是一种特殊的接口!!)。
常用的标注:
@Override:表示覆盖父类的方法
当一个方法使用了此标注以后,编译器在编译时会检查所标注的方法是否满足覆盖的条件,如果不满足将会编译失败。
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
标注按照方法的个数可以分为三类:
1.标记标注
没有值
用法:@标注明
2.单值标注
一个值
用法:@标注名(属性=值)
3.普通标注
多个值
用法:@标注名(属性=值,属性=值)
自定义标注类型;
定义一个标识标注:
Public @interface MyAnno{ //标注就是一种特殊的接口,和定义接口就差一个字符
}
定义标注可以放的位置:
@Target({…})//指定标注能放的位置
Public @interface MyAnno{ //单值标注,值为ElementType数组
}
ElementType是一个枚举类型,不同的枚举值表示标注能放在不同的位置:
@Target({ElmentType.FIELD,ElementType.METHOD})//表示标注只能放在属性和方法上
Public @interface MyAnno{
}
定义标注的生命周期;
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(…)//标注的生命周期,值为RetentionPolicy类型
Public @interface MyAnno{
}
RetentionPolicy也是一个枚举类型,不同的枚举值表示标注具备不同的生命周期:
SOURCE:标注在编译后消失(source)
CLASS:标注在类加载后消失
RUNTIME:标注不消失,运行时存在于JVM中
一个类被添加标注,并且标注在运行时不消失,就可以使用反射获得被标注的信息。
For(Method m:Student.Class.getMethods()){
If(m.isAnnotationPresent(MyAnno.class)){//判断方法上面是否有标注或者注解
System.out.println(m.getName());
}
}
在获得被标注的方法的同时,还能获得方法上的标注,调用标注对象的方法就能获得相应的属性值:
For(Method m:Student.class.getMethods()){
If(m.isAnnotationParesent(MyAnno.class)){
MyAnno ma=m.getAnnotation(MyAnno.class);//获取标注对象
System.out.println(ma.value());//获取标注对象的值
}
}
只要在在自定义标注时,指定生命周期为RUNTIME,就可以使用反射对一个类进行标注分析,获得这个类中所有标注的信息,可以对一个类或者对象进行额外的操作,实现额外的功能。
标注的缺点:
标注和源代码是强耦合的,所以不适用于需求多变的情况。
标注是配合反射用的,反射的运行效率较低。
标注的实际作用:
可以用于单元测试中:
把希望测试的方法使用标注标记
使用反射获得所有待测试的方法对象
为每个方法对象分配一个线程
使用反射调用方法对象进行测试
单元测试框架
使用标注实现
为方法添加一个标注即可测试运行
JUnit常用标注:
@Test:待测试的方法,可以有多个
@Test(timeout=xxxx):指定毫秒内执行完
@Before:在每个测试方法前执行
@After:在每个测试方法后执行
Annotation的作用:
不是程序本身,可以对程序做出解释。(和注释作用相同)
可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别。)
Annotation的格式:
注释是以”@注释名”,在代码中存在,还可以添加一些参数值,例如:@SuppressWarnings(value=”unchecked”).
Annotation如何使用;
可以附加在package,class,method,field等上面,相当于给他们了额外的辅助信息,我们可以通过反射机制编程实现对这些数据的访问。
@Override(内置注解)
定义在java.lang.Override中,此注释只适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明。
@Deprecated(遗弃)
定义在Java.lang.Deprecate中,此注释可用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
@SuppressWarings(镇压警告)
定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
与前两个注释有所不同,需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:
参数 说明
Deprecation 使用了过时的类或方法的警告
unchecked 执行了未检查的转换时的警告,如使用集合时未指定泛型
Fallthroough 当在switch语句使用时发生case穿透
Path 在类路径、源文件路径等中有不存在路径的警告
Serial 当在可序列化的类上缺少serialVerSionUID定义时的警告
Finally 任何finally子句不能完成时的警告
All 关于以上所有情况的警告
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”,”deprecation”})
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
要点:
@interface用来声明一个注解
格式为:public @interface 注解名 {定义体}
其中的每一个方法实际上是声明了一个配置参数。
方法名称就是参数的名称
返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、 enum)。
可以通过default来声明参数的默认值。
如果只有一个参数成员,一般参数名为value。
类图:
在项目

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值