常用类
String类
java.lang.String
- 关于Java JDK中内置的一个类:java.lang.String
1、String表示字符串类型,属于引用数据类型,不属于基本数据类型。
2、在java中随便使用双引号括起来的都是String对象。例如:"abc","def","hello world!",这是3个String对象。
3、java中规定,双引号括起来的字符串,是不可变的,也就是说"abc"自出生到最终死亡,不可变,不能变成"abcd",也不能变成"ab"。(不可变是指对象不可变)
4、在JDK当中双引号括起来的字符串,例如:"abc" "def"都是直接存储在“方法区”的“字符串常量池”当中的。
5、为什么SUN公司把字符串存储在一个“字符串常量池”当中呢?
- 因为字符串在实际的开发中使用太频繁,为了执行效率,所以把字符串放到了方法区的字符串常量池当中。
6、记住:堆区中是运行期分配的,常量池中是编译器分配的
- string字符串存储原理 P424
//String s = new String("ABC"); 这一行表示两个对象 在方法1区常量池一个 堆内存一个
String s = "ABC" // 这就是创建对象 s保存的是字符串 ABC 在常量池中的内存地址
String s = "ABC"+"DEF" ; // 常量池中表示三个对象: "ABC" "DEF" "ABCDEF"
第一行代码原理:
- 是将方法区中的字符串常量存储的 "ABC" 的内存地址,复制一份给堆内存的String类型的对象
即String类型的对象指向字符串常量区的 "ABC" - 然后栈内存的 引用 s , 指向堆内存的String类型的对象(将内存地址复制一份在赋值给s)
第二行代码的原理:
- 栈内存引用 s 直接 指向方法区字符串常量区的 "ABC"
- s 引用 保存的是字符串对象在字符串常量池的内存地址
第三行代码的原理:
- 运行时 对字符串进行拼接 会放在堆内存中
- 若常量池中没有此对象 先在常量池中创建此对象 然后返回此对象的内存地址
内存图如下:
注意:
- 只要采用双引号赋值字符串,那么在编译期将会放到方法区中的字符串的常量池里
- 如果是运行时对字符串相加或相减会放到堆中
- 放之前会先验证方法区中是否含有相同的字符串常量,如果存在,把地址返回,如不存在,先将字符串常量放到池中,然后再返回该对象的地址
- String s1 = “abc” 和 String s2 = new String(“abc”)
分析:这是使用new的方式创建的字符串对象。这个代码中的"xy"是从哪里来的?
String s3 = new String("xy");
- 凡是双引号括起来的都在字符串常量池中有一份。
- new对象的时候一定在堆内存当中开辟空间。
- 字符串之间的比较
- 通过以下案例的学习,我们知道了,字符串对象之间的比较不能使用“==”
- "=="不保险。应该调用String类的equals方法,String类已经重写了equals方法,
public class StringTest02 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
// 分析结果是true还是false?
// == 双等号比较的是不是变量中保存的内存地址?是的。
System.out.println(s1 == s2); // true
分析:
- "hello" 是存储在方法区的字符串常量池当中,所以这个 "hello" 不会新建。(因为这个对象已经存在了!)
String x = new String("xyz");
String y = new String("xyz");
System.out.println(x == y); //false
- 分析结果是true还是false?
== 双等号比较的是不是变量中保存的内存地址?是的。
- 分析以下程序,一共创建了几个对象
public class StringTest03 {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
}
}
- 一共3个对象:
方法区字符串常量池中有1个:"hello"
堆内存当中有两个String对象。
String 类的构造方法
- 关于String类的构造方法
- 第一个:String s = new String("");
要在常量池生成一个对象,堆内存生成一个对象,效率较低
- 第二个:String s = " "; 最常用效率较高
- 第三个:String s = new String(char数组);
- 第四个:String s = new String(char数组,起始下标,长度);
- 第五个:String s = new String(byte数组);
- 第六个:String s = new String(byte数组,起始下标,长度)
- 案例:
public class StringTest04 {
public static void main(String[] args) {
// 创建字符串对象最常用的一种方式
String s1 = "hello world!";
// s1这个变量中保存的是一个内存地址。
// 按说以下应该输出一个地址。
// 但是输出一个字符串,说明String类已经重写了toString()方法。
System.out.println(s1);//hello world!
System.out.println(s1.toString()); //hello world!
// 这里只掌握常用的构造方法。
byte[] bytes = {97, 98, 99}; // 97是a,98是b,99是c
String s2 = new String(bytes);
// 前面说过:输出一个引用的时候,会自动调用toString()方法,默认Object的话,会自动输出对象的内存地址。
// 通过输出结果我们得出一个结论:String类已经重写了toString()方法。
// 输出字符串对象的话,输出的不是对象的内存地址,而是字符串本身。
System.out.println(s2.toString()); //abc
System.out.println(s2); //abc
// String(字节数组,数组元素下标的起始位置,长度)
// 将byte数组中的一部分转换成字符串。
String s3 = new String(bytes, 1, 2);
System.out.println(s3); // bc
// 将char数组全部转换成字符串
char[] chars = {'我','是','中','国','人'};
String s4 = new String(chars);
System.out.println(s4);
// 将char数组的一部分转换成字符串
String s5 = new String(chars, 2, 3);
System.out.println(s5);
String s6 = new String("helloworld!");
System.out.println(s6); //helloworld!
}
}
String类的常用方法
- String类常用的方法 (多敲 、 多练习 )
- 只要是对象就能“点.”
- 需要掌握的方法:
- charAt(int index [下标] )
// 对象.charAt(int index)
char c = "中国人".charAt(1); // "中国人"是一个字符串String对象。
System.out.println(c); // 国
- java.lang.ArrayIndexOutOfBoundsException
- boolean contains(CharSequence s)
判断前面的字符串中是否包含后面的子字符串。
// boolean contains(CharSequence s)
System.out.println("HelloWorld.java".contains(".java")); // true
System.out.println("http://www.baidu.com".contains("https://")); // false
- boolean endsWith(String suffix)
判断当前字符串是否以某个子字符串结尾。
System.out.println("test.txt".endsWith(".java")); // false
System.out.println("test.txt".endsWith(".txt")); // true
System.out.println("fdsajklfhdkjlsahfjkdsahjklfdss".endsWith("ss")); // true
- boolean equals(Object anObject)
比较两个字符串必须使用equals方法,不能使用“==”
equals方法有没有调用compareTo方法?
老版本可以看一下。JDK13中并没有调用compareTo()方法。
compareTo 与equals 方法的区别:
- equals只能看出相等不相等。
- compareTo方法可以看出是否相等,并且同时还可以看出谁大谁小。
System.out.println("abc".equals("abc")); // true
- boolean equalsIgnoreCase(String anotherString)
判断两个字符串是否相等,并且同时忽略大小写。
System.out.println("ABc".equalsIgnoreCase("abC")); // true
- byte[] getBytes()
- 将字符串对象转换成字节数组
byte[] bytes = "abcdef".getBytes();
for(int i = 0; i < bytes.length; i++){
System.out.println(bytes[i]);
}
- int indexOf(String str)
- 判断某个子字符串在当前字符串中第一次出现处的索引(下标)。
System.out.println("oraclejavac++.netc#phppythonjavaoraclec++".indexOf("java")); // 6
- boolean isEmpty()
- 判断某个字符串是否为“空字符串”。底层源代码调用的应该是字符串的length()方法。
//String s = "";
String s = "a";
System.out.println(s.isEmpty());
- int length()
- 面试题:判断数组长度和判断字符串长度不一样
- 判断数组长度是length属性,判断字符串长度是length()方法。
System.out.println("abc".length()); // 3
System.out.println("".length()); // 0
- int lastIndexOf(String str)
- 判断某个子字符串在当前字符串中最后一次出现的索引(下标)
System.out.println("oraclejavac++javac#phpjavapython".lastIndexOf("java")); //22
- String replace(CharSequence target, CharSequence replacement)
- 替换
// String的父接口就是:CharSequence
String newString = "http://www.baidu.com".replace("http://", "https://");
System.out.println(newString); //https://www.baidu.com
// 把以下字符串中的“=”替换成“:”
String newString2 = "name=zhangsan&password=123&age=20".replace("=", ":");
System.out.println(newString2); //name:zhangsan&password:123&age:20
- String[] split(String regex)
- 拆分字符串
String[] ymd = "1980-10-11".split("-"); //"1980-10-11"以"-"分隔符进行拆分。
for(int i = 0; i < ymd.length; i++){
System.out.println(ymd[i]);
}
String param = "name=zhangsan&password=123&age=20";
String[] params = param.split("&");
for(int i = 0; i
System.out.println(params[i]);
// 可以继续向下拆分,可以通过“=”拆分。
}
○ boolean startsWith(String prefix)
// 判断某个字符串是否以某个子字符串开始。
System.out.println("http://www.baidu.com".startsWith("http")); // true
System.out.println("http://www.baidu.com".startsWith("https")); // false
- String substring(int beginIndex) 参数是起始下标。
- 截取字符串
System.out.println("http://www.baidu.com".substring(7)); //www.baidu.com
- String substring(int beginIndex, int endIndex)
- beginIndex起始位置(包括)
- endIndex结束位置(不包括)
System.out.println("http://www.baidu.com".substring(7, 10)); //www
- char[] toCharArray()
- 将字符串转换成char数组
char[] chars = "我是中国人".toCharArray();
for(int i = 0; i < chars.length; i++){
System.out.println(chars[i]);
}
- String toLowerCase()
- 转换为小写
System.out.println("ABCDefKXyz".toLowerCase());
- String toUpperCase();
System.out.println("ABCDefKXyz".toUpperCase());
- String trim();
- 去除字符串前后空白
System.out.println(" hello world ".trim());
- String中只有一个方法是静态的,不需要new对象
- 这个方法叫做valueOf
- 作用:将“非字符串”转换成“字符串”
String s1 = String.valueOf(true);
//String s1 = String.valueOf(100);
//String s1 = String.valueOf(3.14);
// 这个静态的valueOf()方法,参数是一个对象的时候,会自动调用该对象的toString()方法吗?
String s1 = String.valueOf(new Customer());
//System.out.println(s1); // 没有重写toString()方法之前是对象内存地址 com.bjpowernode.javase.string.Customer@10f87f48
System.out.println(s1); //我是一个VIP客户!!!!
// 我们是不是可以研究一下println()方法的源代码了?
System.out.println(100);
System.out.println(3.14);
System.out.println(true);
Object obj = new Object();
// 通过源代码可以看出:为什么输出一个引用的时候,会调用toString()方法!!!!
// 本质上System.out.println()这个方法在输出任何数据的时候都是先转换成字符串,再输出。
System.out.println(obj);
System.out.println(new Customer());
- 了解的方法
- int compareTo(String anotherString)
- 字符串之间比较大小不能直接使用 > < ,需要使用compareTo方法。
public class StringTest05 {
public static void main(String[] args) {
int result = "abc".compareTo("abc");
System.out.println(result); //0(等于0) 前后一致 10 - 10 = 0
int result2 = "abcd".compareTo("abce");
System.out.println(result2); //-1(小于0) 前小后大 8 - 9 = -1
int result3 = "abce".compareTo("abcd");
System.out.println(result3); // 1(大于0) 前大后小 9 - 8 = 1
// 拿着字符串第一个字母和后面字符串的第一个字母比较。能分胜负就不再比较了。
System.out.println("xyz".compareTo("yxz")); // -1
}
}
class Customer {
// 重写toString()方法
@Override
public String toString() {
return "我是一个VIP客户!!!!";
}
}
StringBuffer类 与StringBudilder[P444-P445]
StringBuffer
底层:是一个byte数组,初始化容量是16;将字符串放到了StringBuffer里面了。
- 思考:
我们在实际的开发中,如果需要进行字符串的频繁拼接,会有什么问题?
- 因为java中的字符串是不可变的,每一次拼接都会产生新字符串。这样会占用大量的方法区内存。造成内存空间的浪费。
- String s = "abc";
s += "hello";
就以上两行代码,就导致在方法区字符串常量池当中创建了3个对象:
- "abc"
- "hello"
- "abchello"
public class StringBufferTest01 {
public static void main(String[] args) {
String s = "";
// 这样做会给java的方法区字符串常量池带来很大的压力。
for(int i = 0; i < 100; i++){
//s += i;
s = s + i;
System.out.println(s);
}
}
}
- 如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的:
- java.lang.StringBuffer
- java.lang.StringBuilder
- 如何优化StringBuffer的性能?
- 在创建StringBuffer的时候尽可能给定一个初始化容量。
- 最好减少底层数组的扩容次数。预估计一下,给一个大一些初始化容量。
- 关键点:给一个合适的初始化容量。可以提高程序的执行效率。
- 拼接字符串,以后拼接字符串统一调用 append()方法。实例方法
- append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。
- StringBuffer sb = new StringBuffer(100);
括号里面的100是初始容量
public class StringBufferTest02 {
public static void main(String[] args) {
// 创建一个初始化容量为16个byte[] 数组。(字符串缓冲区对象)
StringBuffer stringBuffer = new StringBuffer();
// 拼接字符串,以后拼接字符串统一调用 append()方法。
// append是追加的意思。
stringBuffer.append("a");
stringBuffer.append("b");
stringBuffer.append("d");
stringBuffer.append(3.14);
stringBuffer.append(true);
// append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。
stringBuffer.append(100L);
System.out.println(stringBuffer.toString());
// 指定初始化容量的StringBuffer对象(字符串缓冲区对象)
StringBuffer sb = new StringBuffer(100);
sb.append("hello");
sb.append("world");
sb.append("hello");
sb.append("kitty");
System.out.println(sb);
}
}
java.lang.StringBuilder
- tringBuffer和StringBuilder的区别?
- StringBuffer中的方法都有:synchronized关键字修饰。表示StringBuffer在多线程环境下运行是安全的。
- StringBuilder中的方法都没有:synchronized关键字修饰,表示StringBuilder在多线程环境下运行是不安全的。
StringBuffer是线程安全的。
StringBuilder是非线程安全的。
public class StringBuilderTest01 {
public static void main(String[] args) {
// 使用StringBuilder也是可以完成字符串的拼接。
StringBuilder sb = new StringBuilder();
sb.append(100);
sb.append(true);
sb.append("hello");
sb.append("kitty");
System.out.println(sb);
}
}
String类的面试题
- String为什么是不可变的?
我看过源代码,String类中有一个byte[]数组,这个byte[]数组采用了final修饰,因为数组一旦创建长度不可变,并且被final修饰的引用一旦指向某个对象之后,不可再指向其它对象,所以String是不可变的!
"abc" 无法变成 "abcd"
- StringBuilder/StringBuffer为什么是可变的呢?
我看过源代码,StringBuffer/StringBuilder内部实际上是一个byte[]数组,这个byte[]数组没有被final修饰,StringBuffer/StringBuilder的初始化容量我记得应该是16,当存满之后会进行扩容,底层调用了数组拷贝的方法System.arraycopy()...是这样扩容的。所以StringBuilder/StringBuffer适合于使用字符串的频繁拼接操作。
- 案例
public class StringBufferTest04 {
public static void main(String[] args) {
// 字符串不可变是什么意思?
// 是说双引号里面的字符串对象一旦创建不可变。
String s = "abc"; //"abc"放到了字符串常量池当中。"abc"不可变。
// s变量是可以指向其它对象的。
// 字符串不可变不是说以上变量s不可变。说的是"abc"这个对象不可变。
s = "xyz";//"xyz"放到了字符串常量池当中。"xyz"不可变。
}
}
- 面试题
public class StringTest1{
public static void main (String[] args){
String a = "java2";
final String b = "java" ;
String d = "java";
String c = b + 2 ;
String e = d + 2 ;
System.out.println(a == c);
System.out.println(a == e);
}
}
代码理解如下:
第四行代码:final 修饰的引用 一旦指向某个对象 就不能在指向另一个对象
第五行代码:因为字符串存储在字符串常量池 所以 变量b 和变量d 指向的是字符串常量池中的同一个常量
第六行代码:因为 变量b 是final 修饰的,且为常量 所以变量b 会在编译期 前替换成值, jvm就会识别,即c的值会在编译期确定
记住这个结论:如果运算时,等号右边有一“运算数”不为常量,则得到的结果相当于new创建的一个新的String类型的对象
第七行代码: d+2 这里的d是一个变量 没有被final修饰
编译期:jvm检查语法,不会去识别这个 d 的具体的值,符合语法,编译通过。
运行期:完成 String 字符串的运算 在堆内存开辟地址 然后在将内存地址赋值给e
内存图如下:
反编译程序如下:
八种包装类 [P446-P447]
基本概念
1、java中为8种基本数据类型又对应准备了8种包装类型。8种包装类属于引用数据类型,父类是Object。
2、思考:为什么要再提供8种包装类呢?
因为8种基本数据类型不够用。
所以SUN又提供对应的8种包装类型。
public class IntegerTest01 {
//入口
public static void main(String[] args) {
// 有没有这种需求:调用doSome()方法的时候需要传一个数字进去。
// 但是数字属于基本数据类型,而doSome()方法参数的类型是Object。
// 可见doSome()方法无法接收基本数据类型的数字。那怎么办呢?可以传一个数字对应的包装类进去。
// 把100这个数字经过构造方法包装成对象。
MyInt myInt = new MyInt(100);
// doSome()方法虽然不能直接传100,但是可以传一个100对应的包装类型。
doSome(myInt);
}
public static void doSome(Object obj){
//System.out.println(obj);
System.out.println(obj.toString());
}
}
包装类型
- 8种基本数据类型对应的包装类型名是什么?
基本数据类型 |
包装类型 |
byte |
java.lang.Byte(父类Number) |
shot |
java.lang.Short(父类Number) |
int |
java.lang.Integer(父类Number) |
long |
java.lang.Long(父类Number) |
float |
java.lang.float(父类Number) |
double |
java.lang.Double(父类Number) |
boolean |
java.lang.Boolean(父类Object) |
char |
java.lang.Character(父类Object) |
- 以上八种包装类中,重点以java.lang.Integer为代表进行学习,其它的类型照葫芦画瓢就行。
- 八种包装类中其中6个都是数字对应的包装类,他们的父类都是Number,可以先研究一下Number中公共的方法:
Number是一个抽象类,无法实例化对象
Number类
Number类中有这样的方法:
- byte byteValue() 以 byte 形式返回指定的数值。
- abstract double doubleValue()以 double 形式返回指定的数值。
- abstract float floatValue()以 float 形式返回指定的数值。
- abstract int intValue()以 int 形式返回指定的数值。
- abstract long longValue()以 long 形式返回指定的数值。
- short shortValue()以 short 形式返回指定的数值。
这些方法其实所有的数字包装类的子类都有,这些方法是负责拆箱的。
public class IntegerTest02 {
public static void main(String[] args) {
// 123这个基本数据类型,进行构造方法的包装达到了:基本数据类型向引用数据类型的转换。
// 基本数据类型 -(转换为)->引用数据类型(装箱)
Integer i = new Integer(123);
// 将引用数据类型--(转换为)-> 基本数据类型
float f = i.floatValue();
System.out.println(f); //123.0
// 将引用数据类型--(转换为)-> 基本数据类型(拆箱)
int retValue = i.intValue();
System.out.println(retValue); //123
}
}
Integer类的构造方法
- 关于Integer类的构造方法,有两个:
- Integer(int)
- Integer(String) (装箱)
- 案例如下:
public class IntegerTest03 {
public static void main(String[] args) {
// Java9之后不建议使用这个构造方法了。出现横线表示已过时。
// 将数字100转换成Integer包装类型(int --> Integer)
Integer x = new Integer(100);
System.out.println(x);
// 将String类型的数字,转换成Integer包装类型。(String --> Integer)
Integer y = new Integer("123");
System.out.println(y);
// double -->Double
Double d = new Double(1.23);
System.out.println(d);
// String --> Double
Double e = new Double("3.14");
System.out.println(e);
}
}
- 通过访问包装类的常量,来获取最大值和最小值(了解)
- 案例如下:
public class IntegerTest04 {
public static void main(String[] args) {
// 通过访问包装类的常量,来获取最大值和最小值
System.out.println("int的最大值:" + Integer.MAX_VALUE);
System.out.println("int的最小值:" + Integer.MIN_VALUE);
System.out.println("byte的最大值:" + Byte.MAX_VALUE);
System.out.println("byte的最小值:" + Byte.MIN_VALUE);
}
}
自动装箱和自动拆箱(运算的时候,注意它的触发机制)
- 好消息:在java5之后,引入了一种新特性,自动装箱和自动拆箱
- 自动装箱:基本数据类型自动转换成包装类。
- 自动拆箱:包装类自动转换成基本数据类型。
- 有了自动拆箱之后,Number类中的方法就用不着了!
- 自动装箱和自动拆箱的好处?
- 方便编程
- 基本数据类型 --(自动转换)--> 包装类型:自动装箱
- 包装类型 --(自动转换)--> 基本数据类型:自动拆箱
- Integer z = 1000; 等同于:Integer z = new Integer(1000);
- z是一个引用,z是一个变量,z还是保存了一个对象的内存地址。
- == 这个运算符不会触发自动拆箱机制。(只有 + - * / 等运算的时候才会。)
// z是一个引用,z是一个变量,z还是保存了一个对象的内存地址。
Integer z = 1000; // 等同于:Integer z = new Integer(1000);
// 分析为什么这个没有报错呢?
// +两边要求是基本数据类型的数字,z是包装类,不属于基本数据类型,这里会进行自动拆箱。 将z转换成基本数据类型
// 在java5之前你这样写肯定编译器报错。
System.out.println(z + 1);
public class IntegerTest05 {
public static void main(String[] args) {
// 900是基本数据类型
// x是包装类型
// 基本数据类型 --(自动转换)--> 包装类型:自动装箱
Integer x = 900;
System.out.println(x);
// x是包装类型
// y是基本数据类型
// 包装类型 --(自动转换)--> 基本数据类型:自动拆箱
int y = x;
System.out.println(y);
Integer a = 1000; // Integer a = new Integer(1000); a是个引用,保存内存地址指向对象。
Integer b = 1000; // Integer b = new Integer(1000); b是个引用,保存内存地址指向对象。
// == 比较的是对象的内存地址,a和b两个引用中保存的对象内存地址不同。
// == 这个运算符不会触发自动拆箱机制。(只有+ - * /等运算的时候才会。)
System.out.println(a == b); //false
}
}
Integer面试重要题目
- java中为了提高程序的执行效率,将[-128到127]之间所有的包装对象提前创建好,放到了一个方法区的“整数型常量池”当中了,目的是只要用这个区间的数据不需要再new了,直接从整数型常量池当中取出来。
- 原理:x变量中保存的对象的内存地址和y变量中保存的对象的内存地址是一样的。
这个题目是Integer非常重要的面试题。
public class IntegerTest06 {
public static void main(String[] args) {
Integer a = 128;
Integer b = 128;
System.out.println(a == b); //false
Integer x = 127;
Integer y = 127;
// == 永远判断的都是两个对象的内存地址是否相同。
System.out.println(x == y); //true
}
}
程序内存图:
池就是缓存机制
Integer类当中常用的方法
- 网页上文本框中输入的100实际上是"100"字符串。后台数据库中要求存储100数字,此时java程序需要将"100"转换成100数字。
- 编译的时候没问题,一切符合java语法,运行时会不会出问题呢?
- 不是一个“数字”可以包装成Integer吗?
- 不能。运行时出现异常 java.lang.NumberFormatException
Integer a = new Integer("123");
//Integer a = new Integer("中文"); 这是不行的
- static int parseInt(String s)(重点方法)
public class IntegerTest07 {
public static void main(String[] args) {
// 手动装箱
Integer x = new Integer(1000);
// 手动拆箱。
int y = x.intValue();
System.out.println(y);
// 重点方法
// static int parseInt(String s)
// 静态方法,传参String,返回int
int retValue = Integer.parseInt("123"); // String -转换-> int
//int retValue = Integer.parseInt("中文"); // NumberFormatException
System.out.println(retValue + 100);
// 照葫芦画瓢
double retValue2 = Double.parseDouble("3.14");
System.out.println(retValue2 + 1); //4.140000000000001(精度问题)
float retValue3 = Float.parseFloat("1.0");
System.out.println(retValue3 + 1); //2.0
// -----------------------------------以下内容作为了解,不需要掌握---------------------------------------
// static String toBinaryString(int i)
// 静态的:将十进制转换成二进制字符串。
String binaryString = Integer.toBinaryString(3);
System.out.println(binaryString); //"11" 二进制字符串
// static String toHexString(int i)
// 静态的:将十进制转换成十六进制字符串。
String hexString = Integer.toHexString(16);
System.out.println(hexString); // "10"
// 十六进制:1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a
hexString = Integer.toHexString(17);
System.out.println(hexString); // "11"
//static String toOctalString(int i)
// 静态的:将十进制转换成八进制字符串。
String octalString = Integer.toOctalString(8);
System.out.println(octalString); // "10"
System.out.println(new Object()); //java.lang.Object@6e8cf4c6
// valueOf方法作为了解
//static Integer valueOf(int i)
// 静态的:int-->Integer
Integer i1 = Integer.valueOf(100);
System.out.println(i1);
// static Integer valueOf(String s)
// 静态的:String-->Integer
Integer i2 = Integer.valueOf("100");
System.out.println(i2);
}
}
String int Integer之间互相转换
public class IntegerTest08 {
public static void main(String[] args) {
// String --> int
int i1 = Integer.parseInt("100"); // i1是100数字
System.out.println(i1 + 1); // 101
// int --> String
String s2 = i1 + ""; // "100"字符串
System.out.println(s2 + 1); // "1001"
// int --> Integer
// 自动装箱
Integer x = 1000;
// Integer --> int
// 自动拆箱
int y = x;
// String --> Integer
Integer k = Integer.valueOf("123");
// Integer --> String
String e = String.valueOf(k);
}
}
Date类(Java中对日期的处理)
java中对日期的处理
这个案例最主要掌握:
知识点1:怎么获取系统当前时间
知识点2:String ---> Date
知识点3:Date ---> String
public class DateTest01 {
public static void main(String[] args) throws Exception {
// 获取系统当前时间(精确到毫秒的系统当前时间)
// 直接调用无参数构造方法就行。
Date nowTime = new Date();
// java.util.Date类的toString()方法已经被重写了。
// 输出的应该不是一个对象的内存地址,应该是一个日期字符串。
//System.out.println(nowTime); //Thu Mar 05 10:51:06 CST 2020
// 日期可以格式化吗?
// 将日期类型Date,按照指定的格式进行转换:Date --转换成具有一定格式的日期字符串-->String
// SimpleDateFormat是java.text包下的。专门负责日期格式化的。
/*
yyyy 年(年是4位)
MM 月(月是2位)
dd 日
HH 时
mm 分
ss 秒
SSS 毫秒(毫秒3位,最高999。1000毫秒代表1秒)
注意:在日期格式中,除了y M d H m s S这些字符不能随便写之外,剩下的符号格式自己随意组织。
*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
//SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
//SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
String nowTimeStr = sdf.format(nowTime);
System.out.println(nowTimeStr);
// 假设现在有一个日期字符串String,怎么转换成Date类型?
// String --> Date
String time = "2008-08-08 08:08:08 888";
//SimpleDateFormat sdf2 = new SimpleDateFormat("格式不能随便写,要和日期字符串格式相同");
// 注意:字符串的日期格式和SimpleDateFormat对象指定的日期格式要一致。不然会出现异常:java.text.ParseException
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
Date dateTime = sdf2.parse(time);
System.out.println(dateTime); //Fri Aug 08 08:08:08 CST 2008
}
}
获取毫秒数
- 获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数。
1秒 = 1000毫秒
public class DateTest02 {
public static void main(String[] args) {
// 获取自1970年1月1日 00:00:00 000到当前系统时间的总毫秒数。
long nowTimeMillis = System.currentTimeMillis();
System.out.println(nowTimeMillis); //1583377912981
// 统计一个方法耗时
// 在调用目标方法之前记录一个毫秒数
long begin = System.currentTimeMillis();
print();
// 在执行完目标方法之后记录一个毫秒数
long end = System.currentTimeMillis();
System.out.println("耗费时长"+(end - begin)+"毫秒");
}
// 需求:统计一个方法执行所耗费的时长
public static void print(){
for(int i = 0; i < 1000000000; i++){
System.out.println("i = " + i);
}
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateTest03 {
public static void main(String[] args) {
// 这个时间是什么时间?
// 1970-01-01 00:00:00 001
Date time = new Date(1); // 注意:参数是一个毫秒
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
// 北京是东8区。差8个小时。
System.out.println(strTime); // 1970-01-01 08:00:00 001
// 获取昨天的此时的时间。
Date time2 = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24);
String strTime2 = sdf.format(time2);
System.out.println(strTime2); //2020-03-04 11:44:14 829
// 获取“去年的今天”的时间
// 自己玩。
}
}
System类的总结
简单总结一下System类的相关属性和方法:
System.out 【out是System类的静态变量。】
System.out.println() 【println()方法不是System类的,是PrintStream类的方法。】
System.gc() 建议启动垃圾回收器
System.currentTimeMillis() 获取自1970年1月1日到系统当前时间的总毫秒数。
System.exit(0) 退出JVM。
System.arrayCopy(五个参数);
Random类(产生随机数)
- 案例如下;
public class RandomTest01 {
public static void main(String[] args) {
// 创建随机数对象
Random random = new Random();
// 随机产生一个int类型取值范围内的数字。
int num1 = random.nextInt();
System.out.println(num1);
// 产生[0~100]之间的随机数。不能产生101。
// nextInt翻译为:下一个int类型的数据是101,表示只能取到100.
int num2 = random.nextInt(101); //不包括101
System.out.println(num2);
}
}
- 课堂练习
import java.util.Arrays;
import java.util.Random;
/*
编写程序,生成5个不重复的随机数[0-100]。重复的话重新生成。
最终生成的5个随机数放到数组中,要求数组中这5个随机数不重复。
*/
public class RandomTest02 {
public static void main(String[] args) {
// 创建Random对象
Random random = new Random();
// 准备一个长度为5的一维数组。
int[] arr = new int[5]; // 默认值都是0
for(int i = 0; i < arr.length; i++){
arr[i] = -1;
}
// 循环,生成随机数
int index = 0;
while(index < arr.length){
// 生成随机数
//int num = random.nextInt(101);
//int num = random.nextInt(6); // 只能生成[0-5]的随机数!
int num = random.nextInt(4); // 只能生成[0-3]的随机数!永远都有重复的,永远都凑不够5个。
System.out.println("生成的随机数:" + num);
// 判断arr数组中有没有这个num
// 如果没有这个num,就放进去。
if(!contains(arr, num)){
arr[index++] = num;
}
}
// 遍历以上的数组
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}
/**
* 单独编写一个方法,这个方法专门用来判断数组中是否包含某个元素
* @param arr 数组
* @param key 元素
* @return true表示包含,false表示不包含。
*/
public static boolean contains(int[] arr, int key){
/*
// 这个方案bug。(排序出问题了。)
// 对数组进行升序
//Arrays.sort(arr);
// 进行二分法查找
// 二分法查找的结果 >= 0说明,这个元素找到了,找到了表示存在!
//return Arrays.binarySearch(arr, key) >= 0;
*/
for(int i = 0; i < arr.length; i++){
if(arr[i] == key){
// 条件成立了表示包含,返回true
return true;
}
}
// 这个就表示不包含!
return false;
}
}
Enum类(枚举)
总结:
1、枚举是一种引用数据类型
2、枚举类型怎么定义,语法是?
enum 枚举类型名{
枚举值1,枚举值2
}
3、结果只有两种情况的,建议使用布尔类型。
结果超过两种并且还是可以一枚一枚列举出来的,建议使用枚举类型。
例如:颜色、四季、星期等都可以使用枚举类型。
4、枚举中的每一个值都是常量
包名的说明
package com.bjpowernode.javase.enum2;
enum是关键字 .后面的功能名字是 标识符,关键字不能做标识符。
案例说明枚举
- 这个案例没有使用java中的枚举,分析以下程序,在设计方面有什么缺陷?
public class EnumTest01 {
public static void main(String[] args) {
//System.out.println(10 / 0); //java.lang.ArithmeticException: / by zero
/*
int retValue = divide(10, 2);
System.out.println(retValue == 1 ? "计算成功" : "计算失败"); // 1
int retValue2 = divide(10, 0);
System.out.println(retValue2 == 0 ? "计算失败" : "计算成功"); // 0
*/
boolean success = divide(10, 0);
System.out.println(success ? "计算成功" : "计算失败");
}
/**
* 需求(这是设计者说的!):以下程序,计算两个int类型数据的商,计算成功返回1,计算失败返回0
* @param a int类型的数据
* @param b int类型的数据
* @return 返回1表示成功,返回0表示失败!
*/
/*
public static int divide(int a, int b){
try {
int c = a / b;
// 程序执行到此处表示以上代码没有发生异常。表示执行成功!
return 1;
} catch (Exception e){
// 程序执行到此处表示以上程序出现了异常!
// 表示执行失败!
return 0;
}
}
*/
// 设计缺陷?在这个方法的返回值类型上。返回一个int不恰当。
// 既然最后的结果只是成功和失败,最好使用布尔类型。因为布尔类型true和false正好可以表示两种不同的状态。
/*
public static int divide(int a, int b){
try {
int c = a / b;
// 返回10已经偏离了需求,实际上已经出错了,但是编译器没有检查出来。
// 我们一直想追求的是:所有的错误尽可能让编译器找出来,所有的错误越早发现越好!
return 10;
} catch (Exception e){
return 0;
}
}
*/
// 这种设计不错。
public static boolean divide(int a, int b){
try {
int c = a / b;
return true;
} catch (Exception e){
return false;
}
}
/*
思考:以上的这个方法设计没毛病,挺好,返回true和false表示两种情况,
但是在以后的开发中,有可能遇到一个方法的执行结果可能包括三种情况,
四种情况,五种情况不等,但是每一个都是可以数清楚的,一枚一枚都是可以
列举出来的。这个布尔类型就无法满足需求了。此时需要使用java语言中的
枚举类型。
*/
}
- 采用枚举的方式改造程序
public class EnumTest02 {
public static void main(String[] args) {
Result r = divide(10, 2);
System.out.println(r == Result.SUCCESS ? "计算成功" : "计算失败");
}
/**
* 计算两个int类型数据的商。
* @param a int数据
* @param b int数据
* @return Result.SUCCESS表示成功,Result.FAIL表示失败!
*/
public static Result divide(int a, int b){
try {
int c = a / b;
return Result.SUCCESS;
} catch (Exception e){
return Result.FAIL;
}
}
}
// 枚举:一枚一枚可以列举出来的,才建议使用枚举类型。
// 枚举编译之后也是生成class文件。
// 枚举也是一种引用数据类型。
// 枚举中的每一个值可以看做是常量。
enum Result{
// SUCCESS 是枚举Result类型中的一个值
// FAIL 是枚举Result类型中的一个值
// 枚举中的每一个值,可以看做是“常量”
SUCCESS, FAIL
}
- switch语句使用枚举
public class SwitchTest {
public static void main(String[] args) {
// switch语句支持枚举类型
// switch也支持String、int
// 低版本的JDK,只支持int
// 高版本的JDK,支持int、String、枚举。
// byte short char也可以,因为存在自动类型转换。
switch (Season.SPRING) {
// 必须省略Season.
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
- 四季枚举的案例
public enum Season {
/*
春夏秋冬
*/
SPRING, SUMMER, AUTUMN, WINTER
}