赞
踩
1)java.lang下的包可以直接使用,无需导包
2)final修饰,不能被继承
3)构造器是私有的,说明不能创建Math类的对象(不能这么使用:Math math = new Math();)
4)Math类里面的属性、方法都由static修饰,说明可以通过Math.属性/方法 调用,不需要创建对象
- public class Demo01 {
- public static void main(String[] args) {
- //常量
- System.out.println(Math.PI);
- //常用方法
- System.out.println("随机数:"+Math.random()); // 取值范围是【0.0,1.0)
- System.out.println("绝对值:"+Math.abs(-6));
- System.out.println("向上取值(往大取)"+Math.ceil(9.1));
- System.out.println("向下取值(往小取)"+Math.floor(9.9));
- System.out.println("四舍五入"+Math.round(3.5));
- System.out.println("最大值"+Math.max(3,6));
- System.out.println("最小值"+Math.min(3,6));
- }
- }
6)分析源码可以发现,Math.random其实就是在调用Random下的nextDouble方法
1)无final修饰,说明是可以创建对象的
无final修饰,说明是可以创建对象的
2)由无参构造器和有参构造器
- import java.util.Random;
-
- //Random类
- public class Demo02 {
- public static void main(String[] args) {
- //Math类产生随机数
- System.out.println(Math.random());
-
- //Random类
- //使用带参数的构造器创建对象,参数是long类型
- Random r1 = new Random(100000L);
- int i= r1.nextInt();//生成一个随机数
- System.out.println(i);
- //多次运行发现输出的i都是同一个数,这是因为seed,也就是种子的意思,seed不变,那么产生的随机数也不会变
- //所以我们用System.currentTimeMillis(当前时间距1970-1-1 00:00:00的时间差,long类型)来作为seed
- Random r2 = new Random(System.currentTimeMillis());
- System.out.println(r2.nextInt());
-
- //使用空参构造器创建对象:表面是在调用无参构造器,其实底层还是调用了有参构造
- //无参构造源码里面 this(seedUniquifier() ^ System.nanoTime());
- //这两者进行异或,由于nanoTime是可变的,所以每次异或出来的值是不同的,所以可以生成不同的随机数
- Random r3 = new Random();
- System.out.println(r3.nextInt());
- //上面是无参的nextInt(),还有一个人带参数的nextInt(int bound),bound为范围
- //这里是10,也就是会生成[0,10)之间的随机数
- System.out.println(r3.nextInt(10));
- //返回[0.0,1.0)之间的double值
- System.out.println(r3.nextDouble());
- }
- }
1)String str="abc"; "abc"是String类的一个实例,也就是类的一个具体的对象
2)字符串是不可变的(可变字符串后面再学)
3)final修饰,不能被继承
4)字符串表面看起来是一个字符串,实际上是存放在一个value[]数组里面(JDK1.8之前是char类型数组,1.8之后源码中是byte类型数组)
debug验证:
5)String str="abc";是类似于自动装箱方式创建对象,还可以通过构造器创建对象
构造器的底层源码功能就是给对象底层的value数组进行赋值
- public static void main(String[] args) {
- String str="abc";
- System.out.println(str);
- //空构造器创建对象
- String s1 = new String();
- String k="";
- /*public String() {
- this.value = "".value;
- }
- 源码中可以看到this.value就是s1.value,而空.value,可以通过debug上面的k看到,空.value里面没有内容,也就是说
- 只是构建了s1这个对象,但是指向的堆是s1:null
- */
-
- //有参构造
- String s2 = new String("abc");
- /*
- public String(String original) {
- this.value = original.value;
- }
- 可以看到,源码中是将传入的original的value作为this.value也就是s2.value
- */
-
- //有参构造,参数为数组
- String s3 = new String(new char[]{'a','b','c'});
- System.out.println(s3);
- /*
- public String(char value[]) {
- this(value, 0, value.length, null);
- }
- */
- }
- //常用方法
- //equals():比较两个字符串的值
- String abc1 = new String("abc");
- String abc2 = new String("abc");
- System.out.println(abc1.equals(abc2)); //返回的是true,这里是比较两个字符串的值
-
- /*
- compareTo()
- 会对字符串的每一个字符遍历进行比较。比较的次数是两个字符串里面长度较短的次数。
- 例如"abc","abcdef"进行比较,a=a,b=b,c=c,那么比较输出的结果就是"abc".length减去"abcdef".length,也就是输出3-6=-3
- 例如"abc","abc"进行比较,都相等,那就是"abc".length减去"abc".length,也就是输出3-3=0
- 例如"abc","acc"进行比较,a=a,b≠c,那么就会输出b和c的ASCII的差值,也就是-1。
- */
- System.out.println(abc1.compareTo(abc2));
-
- //substring():字符串的截取,substring(3):从下标为3(下标从0开始)的开始截取,substring(3,6)截取下标3-5位
- String s6 = new String("abcdefghijk");
- System.out.println(s6.substring(3)); //defghijk
- System.out.println(s6.substring(3,6)); //def
-
- //concat():字符串拼接
- String s7 = new String("aaaaaaa");
- System.out.println(s6.concat(s7));
-
- //replace(a,b):将字符串中的a全部替换为b
- String s8 = new String("abcccba");
- System.out.println(s8.replace("a","k"));
-
- //split("-"):以()内传入的指定的字符串为分隔符,进行分割后组成一个数组
- String s9 = new String("a-b-c-d-f");
- String[] strs = s9.split("-");//Alt+回车,Introduce local variable自动加载,可以看到这里生成的是一个数组
- //对数组进行输出
- System.out.println(Arrays.toString(strs));
-
- //大小写转换toUpperCase():转大写,toLowerCase转小写
- String abc = new String("ABC");
- System.out.println(abc.toLowerCase());
- System.out.println(abc.toLowerCase().toUpperCase());
-
- //去除字符串首尾的空格
- String s10 = new String(" a b c ");
- System.out.println(s10.trim());
-
- //将boolean类型转换为String类型
- System.out.println(String.valueOf(false));
- /*
- public static String valueOf(boolean b) {
- return b ? "true" : "false";
- }
- 查看源码可以看到,将传入的参数b和true比较,如果和true相等,则返回true,如果不等于true,则返回false。
- 因为boolean值只有true和false。
- */
编写一段代码如下
- public static void main(String[] args) {
- String s1="a"+"b"+"c";
- String s2="ab"+"c";
- String s3="a"+"bc";
- String s4="abc";
- String s5="abc"+"";
- }
重新编译这段代码,点击IDEA菜单Build-->Recompile 'xxx.java'
反编译这个class文件,这里我使用了一个在线的反编译网站http://www.javadecompilers.com/,结果如下,可以看到,字符串进行了编译器优化,能直接合并成为完整的字符串。
这段代码内存分析如下
如果用new String来创建一个新的对象
String s6 = new String("abc");
内存分析如下
如果在创建对象时加入变量
- String s7 = "abc";
- String s8= s7+"def";
- System.out.println(s8);
由于在编译String s8= s7+"def"; 的时候,编译器不会知道s7是“abc”,所以不会像上面的代码一样直接优化成“abcdef”。
字符串可以分为两类:不可变字符串(String)、可变字符串(StringBuilder、StringBuffer)
1)属性
StringBuilder继承了它的父类的两个属性(JDK1.8之前是char类型数组,1.8之后源码中是byte类型数组)
value[]:StringBuilder底层的存储
count:value数组中被使用的长度
StringBuilder中有三个构造器
1)空构造器
可以看到空构造器中是调用了父类的有参构造器,并且传了一个值16
于是跳转到父类构造器
可以看到源码中的COMPACT_STRINGS初始定义为true,于是走if为真代码,value数组的长度为16。
所以空构造器就是给当前对象的value[]数组的长度赋初始值16。
2)int有参构造器
可以看到有参构造器也是调用父类的构造器,也就是将我们调用有参构造时传入的数值赋值给value[]数组的长度。
3)string有参构造器
分析后,可以得到:str参数类型的构造器的功能是将value[]数组的长度赋值为str.length+16,
并且将str字符串从下标为0开始放到数组中,将count赋值为数组使用了的长度也就是str的长度
例如,传了一个字符串abc,那么数组为 :
调用构造器代码
- package com.rzd.commonusedclass;
-
- public class Demo05 {
- public static void main(String[] args) {
- //调用StringBuilder空构造器创建StringBuilder对象
- StringBuilder sb1 = new StringBuilder();
- //调用StringBuilder有参构造器创建StringBuilder对象
- StringBuilder sb2 = new StringBuilder(10);
- //这时value[]的长度为16+str.length=19,count=3
- StringBuilder sb3 = new StringBuilder("abc");
- /*如果此时向数组中继续添加字符串,可以使用append方法来添加。
- 可以进行多次添加,这里添加了10个a,又添加了10个b
- 添加10个a后count为13,数组长度为19,可以放得下,
- 再添加10个b后,count数组放不下了,这时底层源码会对数组的长度进行扩容,
- 扩容后数组长度为大于19的数(具体查看源码逻辑),扩容后10个b可以添加到数组中,
- count为13+10=23。
- */
- StringBuilder sb=sb3.append("aaaaaaaaaa").append("bbbbbbbbbb");
- //输出sb时底层完成了将StringBuilder类型转换为String类型后输出
- System.out.println(sb);
- }
- }
1)String是不可变的,如果给str赋值为“abc”,它在内存中会有固定的地址0x99,当把str修改为“abcdef”时,在内存中会重新开辟新的空间,那么str指向的地址也会改变
2)StringBuilder是可变的,利用append方法追加字符串,地址不会改变,可以利用代码测试
- StringBuilder sb4 = new StringBuilder();
- System.out.println(sb4.append("abc")==sb4.append("def"));
运行结果为true。
- public class Demo06 {
- public static void main(String[] args) {
- //StringBuilder和StringBuffe用法
- //增
- StringBuilder sb = new StringBuilder("abcdef");
- sb.append("你好世界");
- System.out.println(sb); //abcdef你好世界
-
- //删
- sb.delete(6,8);//删除数组下标为[6-8)位置上的字符,一个汉字占1个字符
- System.out.println(sb); //abcdef世界
- sb.deleteCharAt(5); //删除位置3的字符
- System.out.println(sb); //abcde世界
-
- //改-->插入
- sb.insert(2,"梦想。。");
- System.out.println(sb); //ab梦想。。cde世界
- //改-->替换
- sb.replace(2,3,"理想"); //[2,3) 将“梦”替换为“理想”
- System.out.println(sb); //ab理想想。。cde世界
-
- //查-->查询单个字符
- System.out.println(sb.charAt(3));
- //查-->查询多个字符
- for (int i = 0; i < sb.length(); i++) {
- System.out.print(sb.charAt(i)+"\t");
- }
- System.out.println();
- //查-->截取
- String str=sb.substring(2,4);
- System.out.println(str);//返回的是一个新的字符串,对StringBuilder没有影响
- }
- }
String和它们的区别是不可变与可变的。
StringBuilder:JDK1.5开始使用,效率高,线程不安全
StringBuffer:JDK1.0开始使用,效率低,线程安全
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。