文章目录
static关键字
static属性虽然定义在类中,但是并不受到实例化对象的限制,所有类中的非static属性(普通属性)都需要在类对象实例化之后才会分配有相应的堆内存空间,才可以进行使用,然而,static属性可以在没有实例化对象的情况下直接通过类名称访问。方法同
static所有方法和属性可以在没有实例化对象的形式下进行访问,而所有的非static操作要求必须存在有实例化对象才可以访问,所以两者是完全矛盾的。
可变参数语法
public [static] 返回值类型 方法名称(参数类型 … 变量){
//相关的处理方法
[ return [返回值]; ]
}
以上所给出的“参数类型 … 变量”在实际接收的时候就是一个数组类型。
String类
在Java中使用双引号“""”定义的内容全部都属于字符串的常量,但是从严格意义上来讲,没有任何一门语言拥有字符串这一概念,也就是说字符串都属于特殊的处理形式,所谓的直接赋值操作,从严格意义上来讲是将一个字符串的匿名对象设置了一个引用关联而已,即:双引号“""”定义的字符串都属于一个String类的匿名对象。
字符串常量池
利用直接赋值的形式所有的字符串对象实际上都会保存在一个对象池里面,对象池的本质就是一个String的数组,在每一次进行新的字符串常量定义时都会首先查找在此对象池中是否存在有内容,如果存在则继续使用,对对象池而言分为两种形式:
- 静态对象池(静态常量池):所有的*.java文件在进行编译的时候都会生成*.class文件,实际上这个文件的主要作用就是进行所有程序的先期的内存分配以及代码结构优化,所有的操作的内容都以常量的形式出现,并且都会为其分配资源完毕;
public class Test {
public static void main(String[] args) {
String strA = "Hello" + "World";
String strB = "HelloWorld";
System.out.println(strA == strB);//运行结果:true
}
}
在本程序中定义的strA对象的内容使用了字符串的连接符连接若干个字符串常量"Hello"+“World”,但是最终的结果发现,它并不是以若干字符串常量的形式出现的,而是以一个整体的形式出现的"HelloWorld",最终的结果发现是true。
静态常量池里面所保存的实际上都是修饰后的内容,例如:对于当前的代码之中出现的"Hello"+“World”,当在程序编译之后会自动的将其转为"HelloWorld"整体,这样就可以提前对程序进行处理了。
- 运行时对象池(运行时常量池):所有的数据内容并不是固定的(可能是通过变量保存的),所以此时它的内容是无法进行固定的,那么作为字符串比较的时候就会出现预期的偏差。
public class Test {
public static void main(String[] args) {
String title = "World";
String strA = "Hello" + title;
String strB = "HelloWorld";
System.out.println(strA == strB);//运行结果:false
}
}
因为对于此时的title变量编译器无法确认它具体是什么内容,也就是说在进行编译的时候该变量是不会被处理的,而在运行的时候才会为这个变量分配相应的内存空间,那么最终的结果就是false。
访问权限修饰符
public、protected、default(不写)、private
异常处理流程
- 当程序之中产生异常之后,实际上会由JVM自动实例化一个与之匹配的异常类对象。
- 此时程序会判断当前的代码之中是否存在有异常的处理语句,如果没有异常处理,则会使用JVM的默认处理形式来进行处理操作,默认方式就是进行异常信息的输出,随后直接中断当前的程序执行。
- 如果此时程序之中存在有异常处理语句,则可以通过try语句捕获当前异常类的实例化对象(引用传递)。
- 捕获的异常类实例化对象需要与每一个catch进行匹配(实例化对象与异常类型之间匹配),如果此时匹配成功,则认为可以使用当前的catch进行异常处理,如果没有匹配成功则向后继续匹配,那么此时有可能出现不能匹配的情况,那么此时就表示该异常无法进行处理。
- 如果在程序语句的最后存在有finally代码,则不管是否处理异常,都会执行finally中的程序语句,但是执行完毕之后则会针对异常是否正确处理进行判断,如果此时异常处理完毕了,则继续向后执行其他代码,如果异常没有执行完毕,则会将未处理的异常交给JVM进行默认处理,于是异常之后的代码将不再执行。
线程运行状态
- 创建状态:开发者定义好了相应的线程类对象,每一个Thread类的实例都表示一个线程对象。
- 就绪状态:多线程的启动依靠的是start()方法,一定要记住,当调用start()方法的时候所有的线程不是立即执行,而是将进入到一个等待状态,等待CPU进行调度。
- 执行状态:当CPU执行调度到了某个线程对象之后,该线程对象执行run()方法或call()方法,但是并不意味着执行的持续占用资源,而是在一段时间之后(一个时间片的时间之后),该线程就需要暂停执行。
- 阻塞状态:当某个线程不再执行时(中断、休眠或调度失效),那么所有的线程将进入到阻塞状态,如果此时线程没有执行完毕则由阻塞状态切换到就绪状态,重新等待CPU执行调度。
- 终止状态:如果多线程的执行体执行完毕或者线程被强制性的结束,那么就将进入到终止状态,终止状态不会再进入到就绪状态,即:该线程对象将不会被继续执行。
生产者与消费者案例
/**
* 基本信息类
*/
class Message{
private String title;
private String info;
//flag=true:表示可以生产,不可以消费
//flag=false:表示可以消费,不可以生产
private boolean flag = true;
public synchronized void set(String title, String info){//生产数据
if(flag==false){//已经生产过了
try {
wait();//等待消费者唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.title = title;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.info = info;
this.flag = false;//生产完毕,修改状态
notify();//唤醒其他等待线程
}
public synchronized void get(){//消费数据
if(this.flag){//没有数据,应该生产
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title+"--"+this.info);
this.flag = true;//消费完毕,修改状态为可生产
notify();//唤醒其他线程
}
}
/**
* 生产类
*/
class Product implements Runnable{
private Message message;
public Product(Message message){
this.message = message;
}
@Override
public void run() {
for (int x=0; x<50; x++){
if(x%2==0){
this.message.set("生产者","我在努力的生产物品!!!");
}else{
this.message.set("消费者","啥也不干,吃吃喝喝~~~");
}
}
}
}
/**
* 消费类
*/
class Consumer implements Runnable{
private Message message;
public Consumer(Message message){
this.message = message;
}
@Override
public void run() {
for (int x=0; x<50; x++){
this.message.get();
}
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
Message message = new Message();
Product product = new Product(message);
Consumer consumer = new Consumer(message);
new Thread(product).start();
new Thread(consumer).start();
}
}
volatile关键字
volatile和同步没有任何的关系,其主要描述的是一种内存变量的快速访问和修改机制。
AutoCloseable接口
语法:
try(AutoCloseable 接口子类 对象 = new 类()){
//编写对应的处理方法
}catch(异常 e){}
代码实现:
/**
* 消息发送类
* 内部类Connect:进行网络连接与关闭
*/
class Message {
class Connect implements AutoCloseable{
public boolean build(){// 网络连接
System.out.println("【Connect】网络连接");
return true;
}
@Override
public void close() throws Exception {// 关闭连接
System.out.println("【Connect】关闭连接,释放资源。。。");
}
}
public void send(String msg) {
try(Connect conn = new Connect()){
if (conn.build()){
if(true){// 手动抛出一个异常进行测试
throw new RuntimeException("剧本异常杀");
}
System.out.println("【消息发送】" + msg);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public class Test{
public static void main(String[] args) {
Message message = new Message();
message.send("你好呀!");
}
}
执行结果:
使用AutoCloseable可以实现自动的资源释放处理操作,在以后进行网络、IO、数据库操作的时候会经常见到此接口的使用。
正则表达式
如果要想进行正则表达式的使用,那么一定要使用大量的正则匹配标记,所有的正则匹配标记都在java.util.regex.Pattern类中定义了,下面进行列出:
1.字符(未加入任何的量词,表示1位):
- x:表示由一个字母“x”所组成;
- \\:匹配一个“\”;
- \t:匹配转义字符“\t”;
- \n:匹配转义字符“\n”;
2.字符范围(未加入任何的量词,表示1位):
- [abc]:匹配“a”、“b”、“c”的任意一位;
- [^abc]:匹配不是“a”、“b”、“c”的任意一位;
- [a-zA-Z]:匹配所有的字母(大小写);
- [0-9]:匹配所有的数字;
3.简化表达式(未加入任何的量词,表示1位):
- “.”:任意字符;
- \d:匹配任意的一位数字,等价于“[0-9]”;
- \D:匹配任意的一位非数字,等价于“[^0-9]”;
- \s匹配任意的一位空字符;
- \S匹配任意的一位非空字符;
- \w:匹配任意的字符,等价于“[a-zA-Z_0-9]”;
- \W:匹配任意的字符,等价于“[^a-zA-Z_0-9]”;
4.边界匹配:
- ^:匹配开始位置;
- $:匹配结束位置;
5.数量描述:如果未加数量描述的定义,则整体在进行处理的时候只能够匹配一次;
- 正则表达式?:表示该正则出现0次或1次;
- 正则表达式*:表示该正则出现0次、1次或多次;
- 正则表达式+:表示该正则出现1次或多次;
- 正则表达式{n}:表示该正则出现正好n次;
- 正则表达式{n,}:表示该正则出现n次以上;
- 正则表达式{n,m}:表示该正则出现n~m次;
6.逻辑运算:
- 正则表达式A正则表达式B:表示在A正则之后紧跟着验证B正则;
- 正则表达式A|正则表达式B:两个正则二选一;
- (X):将多个正则定义为一组进行控制;
transient关键字
现在所使用的序列化属于自动序列化,那么在进行自动序列化的操作过程之中,实际上对象中的所有属性都会被默认进行保存,但是这个时候有些属性可能并不需要进行保存,所以在自动化管理的序列化操作之中,就可以针对于这些不需要保存的属性使用transient来声明。
泛型通配符?
- 设置泛型的下限:? super 类;
例如:“? super String”,表示可以设置的泛型类只能够是String以及其父类Object; - 设置泛型的上限:? extends 类;
例如:“? extends Number”,表示所设置的泛型类型只能够是Number或者其子类;
网络通讯Socket、ServerSocket
在进行通讯的时候,Socket描述的是客户端的连接对象,服务器端获取的Socket的输出流,输出的内容就是客户端的输入,而服务器端获取的Socket实例的输入流就是客户端的输出。
package com.gen;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* 服务器端
*/
class HelloServer{
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);// 设置绑定端口,使用8000以上的
System.out.println("服务器端程序运行,等待客户端连接……");
Socket client = server.accept();// 等待客户端连接
PrintStream out = new PrintStream(client.getOutputStream());// 获取客户端的输出对象
out.println("Hello World");
out.println("!!!");
client.close();
server.close();
}
}
/**
* 客户端
*/
class HelloClient{
public static void main(String[] args) throws IOException {
Socket client = new Socket("127.0.0.1", 9999);// 连接服务器
Scanner scanner = new Scanner(client.getInputStream());// 获取服务器端的输入流
scanner.useDelimiter("\n");
while (scanner.hasNext()){
System.out.println("【服务器回应数据】"+ scanner.next());
}
client.close();
}
}
UDP案例
package com.gen;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* UDP服务器端
*/
class UDPServer{
public static void main(String[] args) throws Exception {
DatagramSocket server = new DatagramSocket(10000);// 服务器地址
String value = "Hello";// 要发送的广播消息
DatagramPacket packet = new DatagramPacket(value.getBytes(), 0 ,value.length(), InetAddress.getByName("localhost"), 9999);
server.send(packet);// 发送数据包
server.close();
}
}
/**
* UDP客户端
*/
class UDPClient{
public static void main(String[] args) throws Exception {
DatagramSocket client = new DatagramSocket(9999);// 连接到指定的监听端口
byte[] data = new byte[1024];// 等待消息的接收
DatagramPacket packet = new DatagramPacket(data, data.length);
client.receive(packet);// 等待接收消息
System.out.println("【UDP客户端】接收到的消息:"+ new String(data));
client.close();
}
}
反射
1.Class类对象实例化:
- 第一种操作:
利用Object类中提供的getClass()方法,通过实例化对象调用获得;
getClass():需要明确的获得使用类的实例化对象。 - 第二种操作:
利用“类.class”的Java原生代码操作实现;
类.class:需要明确的进行操作类的导入处理。 - 第三种操作:
利用Class类中提供的方法进行实例化;
Class.forName():可以通过字符串描述要使用类的名称。
package com.gen;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class claA = new java.util.Date().getClass();
Class claB = java.util.Date.class;
Class claC = Class.forName("java.util.Date");
System.out.println(claA.getName());
System.out.println(claB.getName());
System.out.println(claC.getName());
}
}
执行结果:
java.util.Date
java.util.Date
java.util.Date
2.反射实例化对象
package com.gen;
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("java.util.Date");
Object obj = clazz.getDeclaredConstructor().newInstance();// 实例化对象
System.out.println(obj);
}
}
执行结果:
Wed Jun 10 10:13:18 GMT+08:00 2020
3.反射调用方法invoke()
package com.gen;
import java.lang.reflect.Method;
/**
* 定义一个简单Java类
*/
class Ball{
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.gen.Ball");
Object obj = clazz.getDeclaredConstructor().newInstance();// 获取实例化对象
Method method = clazz.getDeclaredMethod("setBrand", String.class);
method.invoke(obj,"高端篮球");// setter()方法调用
method = clazz.getDeclaredMethod("getBrand");
System.out.println(method.invoke(obj));// getter()方法调用
}
}
执行结果:
高端篮球
事务ACID原则
- 原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency):事务前后数据的完整性必须保持一致。
- 隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
- 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。