文章目录
一、对象内存管理:
- 编译好的Java程序需要运行在JVM中。
- 程序,无论是代码还是数据,都需要存储在内存中。JVM为Java程序提供并管理所需要的内存空间。
- JVM内存分为“堆”、“栈”和“方法区”三个区域,分别用于存储不同的数据。
①堆内存:
- JVM在其内存空间开辟了一个称为“堆”的存储空间;
- 这部分空间用于存储使用使用new关键字所创建的对象。
- 成员变量的生命周期:
- 访问对象需要依靠引用变量。
- 当一个对象没有任何引用时,会被GC(垃圾回收器)进行回收,该对象中的所有成员变量也随之被回收。
- 成员变量的生命周期为:从对象在堆中创建开始到对象被GC回收结束。
②垃圾回收机制:
-
垃圾回收器(Garbage Collection,简称GC)是JVM自带的一个线程(自动运行着的程序),用于回收没有任何引用指向的对象。
-
Java程序员不用担心内存管理,因为垃圾回收器会自动进行内存回首。
-
Java程序的内存泄漏问题:
- 内存泄漏是指——不再使用的内存没有被及时的回收。严重的内存泄漏会因为过多的内存被占用而导致程序的崩溃。
- GC线程判断对象是否可以回收的依据是该对象是否有引用指向,因此,当确定该对象不再使用时,应该及时将其引用设置为null.
-
System.gc()方法:
- GC的回收对于程序员来说是不可见的,并不一定一发现有无引用的对象就立即回收。
- 一般情况下,当我们需要GC线程即刻回收无用对象时,我们可以调用System.gc()方法。
- System.gc()方法用于建议(不一定执行)虚拟机马上调度GC线程回收资源,具体的实现策略取决于不同的JVM系统。
③栈:
- 栈用于存放方法中声明的所有局部变量。
package MyTest;
public class Test{
int a;
public static void main(String[] args) {
Test t = new Test();
t.show(2);
}
public void show(int b){
int c;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
//error:Variable 'c' might not have been initialized
-
分析:一个变量在使用之前必须提前声明并且初始化,对于上面中的实例变量a,会自动初始化为0,所以不用担心;对于变量b,在调用相关函数show时,一定会传入一个参数用于变量b的初始化,所以也不用担心;但是对于变量c来说,仅仅对其进行了声明,并未对其初始化,所以会报错!
-
局部变量的生命周期:
- 一个运行的Java程序从开始到结束会有多次方法的调用。JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间我们称之为该方法的栈帧。
- 一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。当某一个方法调用完成之后,其对应的栈帧将会被清除,局部变量失效。
-
成员变量与局部变量:
- 局部变量:
- 定义在方法中。
- 没有默认值,必须自己设定初始值。
- 方法被调用时,存在栈中,方法调用结束,从栈中清除。
- 成员变量:
- 定义在类中,方法外。
- 有初始默认值,可以不显式初始化。
- 所有类在被实例化后,存在堆中,对象回收时,成员变量失效。
- 局部变量:
④方法区:
- 方法区用于存放类的信息:
- Java程序运行时,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区,==类的各种信息(包括方法)==都在方法区中存储。
- 方法只有一份:
- 当类的信息被加载到方法区时,除了类的类型信息之外,同时在类内的方法定义也被加载到方法区。
- 类在实例化对象时,多个对象会拥有各自在堆中的空间,但是所有实例化对象是共用在方法区中的一份方法定义的。
二、Debug调试:
- 主要使用四个按键
功能 | Eclipse | Idea |
---|---|---|
单步调试,会进入到方法中。 | F5 | F7 |
单步调试,不会进入到方法中。 | F6 | F8 |
结束方法的调试,返回。 | F7 | shift+F8 |
直接跳到下一个断点,若无断点则调试结束。 | F8 | shift+F8 |
- 主要观看两个窗口:
Variables窗口:用于观看相关变量的值。
Watchers窗口:用于添加相关的逻辑表达式,用于判断真假。
三、API文档:
①JDK API:
-
什么是JDK API?
- JDK中包含大量的API类库,所谓的API(应用程序编程接口)就是一些已写好、可供直接调用的功能(在java中这些功能以类的形式封装)。
- JDK API包含的类库功能强大,经常使用的有:字符串操作、集合操作、文件操作、输入输出操作、网络操作、多线程等。
-
JDK包结构:
-
为了便于使用和维护,JDK类库按照包结构划分,不同功能的类划分在不同的包中。
-
经常使用的包有:
包 功能 java.lang Java程序的基础类,如字符串、多线程等,该包中的类的使用频率非常的高,不需要import,可以直接使用。 java.util 常用工具类,如集合、随机数产生器、日历、时钟等 java.io 文件操作、输入/输出操作 java.net 网络操作 java.math 数学运算相关操作 java.security 安全相关操作 java.sql 数据库访问 java.net 处理文字、日期、数字、信息的格式
-
②文件注释规范:
文档注释主要只在三个地方出现:类上面、方法上面、变量上面。
/**
* 这是用于测试功能的一个测试用例! //类功能说明
* @author YiWen Wan //作者
* @version 1.204,06/09/06 //版本
* @see java.lang.StringBuffer //参见
* @since JDK 1.0 //始于JDK版本
* ……
*/
- 实际使用样例:
package MyTest;
/**
* 这是用于测试功能的一个测试用例! //类功能说明
* @author YiWen Wan //作者
* @version 1.204,06/09/06 //版本
* @see java.lang.StringBuffer //参见
* @since JDK 1.0 //始于JDK版本
*/
public class Test {
/**
* 用于输出提示性话语的一个String变量!
*/
public static String string = "Hello World!";
/**
* 主函数
* @param args
*/
public static void main(String[] args) {
int a = 7;
int b = 8;
System.out.println(string);
Plus(a,b);
}
/**
* 用于计算两数加法运算,并限制其输出的一个函数。
* @param num1:参与加法运算的其中一个参数
* @param num2:参与加法运算的另一参数
*/
public static void Plus(int num1,int num2){
int num=-1;
num = num1 + num2;
if (num>=10){
System.out.println(num);
}
}
}
③导出项目的JavaDoc文档:
-
下一步
-encoding utf-8 -charset utf-8
- 这里有的教程会让你写:
-encoding UTF-8 -charset UTF-8 -windowtitle "你的文档在浏览器窗口标题栏显示的内容" -link http://docs.Oracle.com/javase/7/docs/api
两者的区别就在于,有没有和java官方的文档“联动起来”。
- 第一种:
- 第二种:
当你点击java语言中已存在的类时,他会跳转到官方文档!
四、字符串String类:
①String是不变对象:
- java.lang.String使用了final进行修饰,所以不能被继承。
- 字符串底层封装了字符数组以及针对字符数组的操作算法。
- 字符串一旦创建,对象就永运无法改变,但是字符串引用可以重新赋值。
- Java字符串在内存中采用了Unicode编码方式,任何一个字符对应着两个字节的定长编码。
- String基本使用特性进行代码验证:
/**
* String是不变对象,JVM对其做了一个优化,在内存中开辟了一段区域作为常量池,
* 凡是通过“字面量”(直接量)形式创建的字符串对象都会缓存并且重用。因为会重用
* 对象,所以该对象内容不可以改变!
* @author YiWen Wan
*/
public class StringDemo {
public static void main(String[] args) {
String str1 = "Hello World!";
String str2 = "Hello World!";
System.out.println("Java重用了这一个字符串直接量!true or false?");
//直接比较引用是否相等,来进一步说明是否指向了同一片内存区域!
System.out.println(str1==str2);
}
}
//Java重用了这一个字符串直接量!true or false?
//true
- String不变对象的特性进行代码验证:
/**
* 一个有趣的现象!
* 因为对象的内容是不可变的,所以修改原指向的值本质上是重新创建了一个新的字符串,
* 原字符串还保留着,防止引起原同一引用的值发生改变!
* @author YiWen Wan
*/
public class StringDemo {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
//原本str1和str2是指向同一块内存区域的,现在改变str1的值!
str1 = str1+"!";
System.out.println(str1);
System.out.println(str2);
}
}
//Hello!
//Hello
- 当使用new语句创建String对象时,无论内容是否相等,都会强制创建一个新的对象!
/**
* 使用new创建新的String对象时,无论之前是否有一样内容的String对象,
* 都会强制创建一个新的对象!
* @author YiWen Wan
*/
public class StringDemo {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println("分割线:--------------");
System.out.println(str1.equals(str3));
}
}
//true
//false
//true
-
所以当比较两个String类型的对象是否相等时,利用equal函数进行判断更为准确,因为不是指向同一对象的String引用也可能内容相等!
-
对String对象进行拼接之后产生的新对象的特性:
/**
* 测试分割重组的String对象的一些特性!
* @author YiWen Wan
*/
public class StringDemo {
public static void main(String[] args) {
String str1 = "HelloWorld";
/*这里是一个编译器的一个优化措施,编译器在编译源代码时,发现计算表达式的所有参数都是“字面量”,在编译之后就直接会将这些“字面量”直接计算了,并将结果编译到class文件中,所以在执行该条语句的时候相当于:
String str2 = "HelloWorld";
所以后续输出才会是true,这已经不是String的特性了!
*/
String str2 = "Hello" + "World";
System.out.println(str1==str2);
//计算表达式有一方是变量时,就一定会创建一个新的对象,所以才会输出false!
String s = "Hello";
String str3 = s + "World";
System.out.println(str1==str3);
}
}
//true
//false
②修改字符串的性能问题:
- 当字符串频繁进行修改时:
- 此时就会频繁的新建字符串,效率就会大幅度降低,内存使用不高效,性能降低,垃圾回收器来不及收!
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "a";
for (int i=0;i<100000000;i++)
str = str + "a";
System.out.println("Game Over!");
}
}
//结果出不来,一直卡着!
-
所以Java中String是不变对象,目的就是提高了重用性,但是对于频繁修改String对象就考虑的不是很完备,“一刀切”思想!
-
StringBuilder类:
- 为了针对修改字符串的情况,Java提供了StringBuilder类(增、删、改、插)进行处理!
- StringBuilder封装可变的字符串,对象创建之后可以通过调用方法改变其封装的字符序列。
/**
* 用于测试StringBuilder中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "好好学习 ";
//当使用无参数的构造方法时,默认生成的是一个空字符串,可以用来以后加东西!
StringBuilder sb = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder(str);
//①增——append()函数,拼接字符串!
System.out.println(stringBuilder.append("天天向上!").toString());
//②改——replace()函数,用于替代指定范围内的字符串内容!表示范围时注意含头不含尾!
System.out.println(stringBuilder.replace(8,9,"后").toString());
//③删——delete()函数,用于删除指定位置的字符串内容!表示范围时注意含头不含尾!
System.out.println(stringBuilder.delete(0,5).toString());
//④插——insert()函数,用于将指定字符串插入到原字符串指定的范围内!
System.out.println(stringBuilder.insert(2,"向上、向下、向左、向右、向前、"));
System.out.println(stringBuilder.reverse());//反转
}
}
// 好好学习 天天向上!
// 好好学习 天天向后!
// 天天向后!
// 天天向上、向下、向左、向右、向前、向后!
- 针对上上面代码的改进版:
/**
* 用于测试StringBuilder中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("a");
for (int i=0;i<10000000;i++)
stringBuilder.append("a");
System.out.println("Game Over!");
}
}
// Game Over!
- StringBuilder总结:
-
Java中字符串的连接过程就是利用StringBuilder实现的。
- String str = “Hello”; String str1 = str+" World!";
- 实际上:String str1 = new StringBuilder(str).append(" World!");
-
StringBuilder与StringBuffer:
- StringBuffer是线程安全的,同步处理的,性能稍慢。
- StringBuilder是线程非安全的,并发处理的,性能稍快。
-
③String类中的常用函数:
- indexof函数:
- 返回给定字符串位于当前字符串的位置(首位置),如果找不到则返回-1。
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "HelloWorld!";
System.out.println("Length:"+str.length());
System.out.println("位置是:"+str.indexOf("Hello"));
System.out.println("位置是:"+str.indexOf("WYW"));
//验证一下indexof的其他重载函数!
System.out.println("位置是:"+str.indexOf("o"));
//从指定位置开始查找:
System.out.println("位置是:"+str.indexOf("o",5));
//查找最后一次出现的位置:
System.out.println("位置是:"+str.lastIndexOf("o"));
}
}
// Length:11
// 位置是:0
// 位置是:-1
// 位置是:4
// 位置是:6
// 位置是:6
- substring函数:
- 截取指定范围内的字符串。
- 注意:Java API有一个特点——通常使用两个数字表示的范围都是 “含头不含尾” 的!
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "HelloWorld";
System.out.println("截取的字符串为:"+str.substring(0,5));
//当参数变成一个的时候,就变成了一刀切了!
System.out.println("截取的字符串为:"+str.substring(5));
}
}
//截取的字符串为:Hello
//截取的字符串为:World
- trim函数:
- 去掉字符串的前后的空格。
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = " HelloWorld! ";
System.out.println("去掉之前的效果是:"+str);
System.out.println("去掉之后的效果是:"+str.trim());
}
}
// 去掉之前的效果是: HelloWorld!
// 去掉之后的效果是:HelloWorld!
- charAt函数:
- 返回字符串指定位置的字符。
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "HelloWorld";
System.out.println("第6个字符是:"+str.charAt(5));
}
}
//第6个字符是:W
- startsWith函数和endsWith函数:
- 检测一个字符串是否以指定的字符串开始或结尾。
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "HelloWorld";
if (str.startsWith("Hello"))
System.out.println("该字符串是以Hello开始的!");
if (str.endsWith("World"))
System.out.println("该字符串是以World结尾的!");
}
}
//该字符串是以Hello开始的!
//该字符串是以World结尾的!
- toUpperCase函数和toLowerCase函数:
- 将原字符串扎转化为全大写或者全小写!
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "HelloWorld";
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
}
}
//HELLOWORLD
//helloworld
- String.valueOf函数:
- 一组重载的静态方法,将给定的内容转化为字符串。
/**
* 用于测试String中函数特性!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
int a = 10;
double b = 3.14;
char c = 'c';
float d = 3.145f;
System.out.println(String.valueOf(a));
System.out.println(String.valueOf(b));
System.out.println(String .valueOf(c));
System.out.println(String.valueOf(d));
//更加简单的方法,但是效率不高
String str = 10+"";
System.out.println("更加简单的方法:"+str);
//一个小测试
System.out.print("测试结果为:");
System.out.println(1+2);
System.out.print("测试结果为:");
System.out.println(1+"2");
}
}
// 10
// 3.14
// c
// 3.145
// 更加简单的方法:10
// 测试结果为:3
// 测试结果为:12
五、正则表达式:
①正则表达式简介:
-
在实际开发中,经常需要对字符串数据进行一些复杂的匹配、查找、替换等操作。通过正则表达式可以方便的实现字符串的复杂操作。
-
正则表达式是一串特定字符,组成的一个“规则字符串”,这个“规则字符串”是描绘文本规则的工具。正则表达式就是记录文本规则的代码。
-
字符集合:
- [ ]表示一个字符,具体表示什么,要看里面的内容。
正则表达式 | 说明 |
---|---|
[abc] | a、b、c中的任意一个字符 |
[^abc] | 除了a、b、c的任意一个字符 |
[a-z] | a、b、c、……、z中的任意一个字符 |
[a-zA-Z0-9] | a ~ z、A ~ Z、0 ~ 9中的任意一个字符 |
[a-z &&[ ^ bc]] | a ~ z中除了b和c以外的任意一个字符,其中&&表示“与”的关系 |
- 预定义字符:
- 类似于Java中的转义字符。
正则表达式 | 说明 |
---|---|
· | 任意一个字符 |
\d | 任意一个数字字符,相当于[0-9] |
\w | 单词字符,相当于[a-zA-Z0-9] |
\s | 空白字符,相当于[\t\n\x0B\f\r] |
\D | 非数字字符 |
\W | 非单词字符 |
\S | 非空白字符 |
- 数量词:
正则表达式 | 说明 |
---|---|
X? | 表示0个或1个X |
X* | 表示0个或任意个X |
X+ | 表示1个到任意个X |
X{n} | 表示n个X |
X{n,} | 表示n个到任意个X |
X{n,m} | 表示n个到m个X |
-
分组“()”:
- ()圆括号表示分组,可以将一系列的正则表达式看作一个整体,分组时可以使用 “|” 表示 “或” 的关系。
- 例如:abcabcabc = (abc){3};将abc看做一个整体进行重复。
- 例如:匹配收集号码前面的区号:(\ +86|0086)?\s?\d{11},圆括号表示这里需要出现“+86”或者“0086”。
- ()圆括号表示分组,可以将一系列的正则表达式看作一个整体,分组时可以使用 “|” 表示 “或” 的关系。
-
" ^ “和” $ ":
- 没有这两个边界字符时,正则表达式是部分匹配。
- 没有这两个边界字符时,正则表达式是部分匹配,部分字符串满足条件就行;单独的" ^ “只看开头是否匹配,单独的” $ "只看结尾是否匹配;当两个一起使用时,才是完全匹配。
- **例如:**匹配用户名规则——从头到尾连续8~10个单词字符
- \w{8,10}
- 如果使用这种写法,则“abcd1234_abcd”是可以验证通过的。
- ^\w{8,10}$
- 如果使用这种写法,需要待检验字符串需要完全匹配,此时“abcd1234_abcd”是无法验证通过的。
- \w{8,10}
- 但是在Java中,就算你不写边界符号,也是会自动加上去的,所以Java默认是全匹配!
- 没有这两个边界字符时,正则表达式是部分匹配。
②String类中有关于正则表达式的方法:
- matches方法:
-
判断当前字符串是否符合提供的正则表达式!matches方法指定的正则表达式就算不指定边界匹配符,也是做全匹配验证的!
-
boolean matches(String regex)
-
/**
* 用于验证Java中正则表达式的使用!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String email = "2000114@WYW.com.cn";//书写输入数据
/*
原本的正则表达式是:\w+@\w+(\.[a-zA-z]+)+但是因为Java中表示转义字符也是使用‘\’来表示,但是式子中的‘\’并非表示Java中的转义;
所以应该让Java看来是一个单纯的‘\’,所以在‘\’前面再加上一个‘\’用来表示!
*/
String regex = "\\w+@\\w+(\\.[a-zA-z]+)+";//书写正则表达式
//matches函数用于验证该字符串是否属于正则表达式!
boolean b = email.matches(regex);
if (b)
System.out.println("这是一个邮箱地址!");
else
System.out.println("这不是一个邮箱地址!");
}
}
//这是一个邮箱地址!
- split方法:
- 使用给定的正则表达式来拆分当前字符串,并且将拆分之后的内容以字符串数组的方法返回。
- String[ ] split(String regex)
/**
* 用于验证Java中正则表达式的使用!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "WYW:007Hello123The456World78765867!";
//正则表达式(以数字进行分割):[0-9]+或者\d+
String regex = "\\d+";
String[] array = str.split(regex);
System.out.println(Arrays.toString(array));
}
}
//[WYW:, Hello, The, World, !]
- 一个有意思的特性:当多次匹配到同一个正则表达式时,将会出现什么样的情况!
/**
* 用于验证Java中正则表达式的使用!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String str = "WYW:007Hello123The456World78765867";
String regex = "\\d";//此时遇到一次数字拆分一次!
String[] array = str.split(regex);
System.out.println(Arrays.toString(array));
}
}
//[WYW:, , , Hello, , , The, , , World]
- 会在中间出现"",一个空的字符串!而且如果在开始或者中间连续匹配时,就会出现空串;但是在末尾出现时,就不会出现空串!
/**
* 用于验证Java中正则表达式的使用!
* @author YiWen Wan
*/
public class StringTest {
public static void main(String[] args) {
String regex = "\\d";//此时遇到一次数字拆分一次!
String str = "534534WYW007Hello123The456World7876";
String[] array = str.split(regex);
System.out.println(Arrays.toString(array));
}
}
//[, , , , , , WYW, , , Hello, , , The, , , World]
- replaceAll方法:
- 将当前字符串中符合正则表达式要求部分的内容转换为给定内容!
- String replaceAll(String regex,String str)
/**
* 用于验证Java中正则表达式的使用!
* @author YiWen Wan
*/
public</