Java进阶部分详解(三)---常见类

简介: 1. 开发过程中经常碰见的类,需要多敲多练!2. 包含内容:String、Data、包装类、随机数和枚举类

常用类

String类


java.lang.String


  1. 关于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、记住:堆区中是运行期分配的,常量池中是编译器分配的
  1. 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 引用 保存的是字符串对象在字符串常量池的内存地址


第三行代码的原理:


  • 运行时 对字符串进行拼接 会放在堆内存中
  • 若常量池中没有此对象 先在常量池中创建此对象 然后返回此对象的内存地址


内存图如下:


网络异常,图片无法展示
|


注意:


  • 只要采用双引号赋值字符串,那么在编译期将会放到方法区中的字符串的常量池里
  • 如果是运行时对字符串相加或相减会放到堆中
  • 放之前会先验证方法区中是否含有相同的字符串常量,如果存在,把地址返回,如不存在,先将字符串常量放到池中,然后再返回该对象的地址


  1. String s1 = “abc” 和  String s2 = new String(“abc”)
    分析:这是使用new的方式创建的字符串对象。这个代码中的"xy"是从哪里来的?

String s3 = new String("xy");

  • 凡是双引号括起来的都在字符串常量池中有一份。
  • new对象的时候一定在堆内存当中开辟空间。
  1. 字符串之间的比较
  • 通过以下案例的学习,我们知道了,字符串对象之间的比较不能使用“==”
  • "=="不保险。应该调用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?
    ==  双等号比较的是不是变量中保存的内存地址?是的。
  1. 分析以下程序,一共创建了几个对象

public class StringTest03 {

   public static void main(String[] args) {

       String s1 = new String("hello");

       String s2 = new String("hello");

   }

}

  • 一共3个对象:
    方法区字符串常量池中有1个:"hello"
    堆内存当中有两个String对象。


String 类的构造方法


  1. 关于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数组,起始下标,长度)


  1. 案例:


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类的常用方法


  1. 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里面了。

  1. 思考:
    我们在实际的开发中,如果需要进行字符串的频繁拼接,会有什么问题?
  • 因为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);

       }

   }

}

  1. 如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的:
  • java.lang.StringBuffer
  • java.lang.StringBuilder


  1. 如何优化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


  1. 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类的面试题


  1. String为什么是不可变的?
     我看过源代码,String类中有一个byte[]数组,这个byte[]数组采用了final修饰,因为数组一旦创建长度不可变,并且被final修饰的引用一旦指向某个对象之后,不可再指向其它对象,所以String是不可变的!
    "abc" 无法变成 "abcd"


  1. StringBuilder/StringBuffer为什么是可变的呢?
     我看过源代码,StringBuffer/StringBuilder内部实际上是一个byte[]数组,这个byte[]数组没有被final修饰,StringBuffer/StringBuilder的初始化容量我记得应该是16,当存满之后会进行扩容,底层调用了数组拷贝的方法System.arraycopy()...是这样扩容的。所以StringBuilder/StringBuffer适合于使用字符串的频繁拼接操作。


  1. 案例

public class StringBufferTest04 {

   public static void main(String[] args) {


       // 字符串不可变是什么意思?

       // 是说双引号里面的字符串对象一旦创建不可变。

       String s = "abc"; //"abc"放到了字符串常量池当中。"abc"不可变。


       // s变量是可以指向其它对象的。

       // 字符串不可变不是说以上变量s不可变。说的是"abc"这个对象不可变。

       s = "xyz";//"xyz"放到了字符串常量池当中。"xyz"不可变。


   }

}



  1. 面试题

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());

   }

}


包装类型


  1. 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


   }

}


获取毫秒数

  1. 获取自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类(产生随机数)

  1. 案例如下;

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);

   }

}

  1. 课堂练习

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是关键字  .后面的功能名字是 标识符,关键字不能做标识符。


案例说明枚举

  1. 这个案例没有使用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语言中的

   枚举类型。

    */


}


  1. 采用枚举的方式改造程序

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

}



  1. 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;

       }


   }

}

  1. 四季枚举的案例

public enum Season {

   /*

   春夏秋冬

    */

   SPRING, SUMMER, AUTUMN, WINTER

}




相关文章
|
16天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
39 17
|
7天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
11天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
51 4
|
12天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
29 2
|
17天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
21天前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
|
21天前
|
Java API Maven
如何使用 Java 字节码工具检查类文件的完整性
本文介绍如何利用Java字节码工具来检测类文件的完整性和有效性,确保类文件未被篡改或损坏,适用于开发和维护阶段的代码质量控制。
|
20天前
|
存储 Java 编译器
java wrapper是什么类
【10月更文挑战第16天】
23 3
|
23天前
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
22 5
|
24天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
30 2