1. String
字符串是我们常用的引用类型的数据结构,看一下用法:
public class HelloWorld { public static void main(String[] args) { String s1 = " hello world "; String s2 = " HELLO WORLD ".toLowerCase(); // 字符串的比较使用equals System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); // true // 获取第一个指定字母的下表 System.out.println(s1.indexOf("l")); // 3 // 获取该字符串出现的最后一个指定字母的下表 System.out.println(s1.lastIndexOf("l")); // 10 // 字符串是否以。。。开头 System.out.println(s1.startsWith("l")); // false // 字符串是否以...结尾 System.out.println(s1.endsWith("l")); // false // 提取字符串的子串 System.out.println(s1.substring(0, 2)); // " h" System.out.println(s1.substring(1, 3)); // " he" // 去除首位空白 System.out.println(s1.trim()); // "hello world" // 去除开头空白 System.out.println(s1.stripLeading()); // "hello world " // 去除结尾空白 System.out.println(s1.stripTrailing()); // " hello world" // 判断是否为空 System.out.println(s1.isEmpty()); // false System.out.println("".isEmpty()); // true // 判断是否是空白字符串 System.out.println(s1.isBlank()); // false System.out.println(" ".isBlank()); // true // 替换字符串 System.out.println(s1.replace('l', 'L')); // " heLLo worLd " 这个是字符 System.out.println(s1.replaceAll("l", "L")); // " heLLo worLd " 这个是字符串,使用正则表达式的字符串 // 分割字符串 String[] c = s1.split(" "); System.out.println(c); // [Ljava.lang.String;@77459877 for (String d : c) { System.out.println(d); // ["", "hello", "world"] } // 拼接字符串 System.out.println(String.join(" ", c)); // " hello world" // 类型转换 System.out.println(String.valueOf(123)); // "123" System.out.println(String.valueOf(45.67)); // "45.67" System.out.println(String.valueOf(true)); // "true" // 字符串转数字 int n = Integer.parseInt("123"); System.out.println(n); // 123 // 字符串转化为 char[] char[] cc = s1.toCharArray(); System.out.println("---"); System.out.println(cc); // hello world 输出的时候自动把这个列表打印成字符串了 System.out.println("---"); for (char m : cc) { System.out.println(m); // [" ", "h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", " "] } // char[] 可以转化为字符串,那么转变完成之后,在修改char[]是否会影响字符串呢 char[] ccc = new char[]{'a', 'b', 'c'}; String cs = new String(ccc); System.out.println(cs); // abc ccc[0] = 'd'; System.out.println(ccc[0]); // d System.out.println(cs); // abc } }
java对String做了特殊处理,因此我们可以直接使用 + 来拼接字符串,但理论上每次拼接字符串,都会生成一个新的字符串,这样会浪费内存,因此java的标准库中提供了StringBuilder,我们首先来看一下源码,大部分的具体实现在这AbstractStringBuilder类中,可以自行去看,基本就是找位置,增删改查操作
// 这不就是上篇说的继承 public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, Comparable<java.lang.StringBuilder>, CharSequence { // 这个就是初始化,方法重载,如果不穿值默认是16,可不传或者 int String CharSequence, 篇幅较长,省略一下 @HotSpotIntrinsicCandidate public StringBuilder() { super(16); } @HotSpotIntrinsicCandidate public StringBuilder(int capacity) { super(capacity); } ... // 这个就是方法重写,做比较的,字串穿比较 @Override public int compareTo(java.lang.StringBuilder another) { return super.compareTo(another); } // 方法重写,这个就是添加操作,当传入的是对象,获取对象的值,然后调用值类型对应的append的方法签名,观察下面的append,发现最后是把this返回去了 // 这个append可以添加各种类型,源码就不一一贴出来了,可以自己去看 @Override public java.lang.StringBuilder append(Object obj) { return append(String.valueOf(obj)); } @Override @HotSpotIntrinsicCandidate public java.lang.StringBuilder append(String str) { super.append(str); return this; } ... // 删除操作。可以看出来,他这个就是告诉起止位置,然后进行删除操作 @Override public java.lang.StringBuilder delete(int start, int end) { super.delete(start, end); return this; } // 删除指定位置 @Override public java.lang.StringBuilder deleteCharAt(int index) { super.deleteCharAt(index); return this; } // 替换,告诉起止位置,以及字符串 @Override public java.lang.StringBuilder replace(int start, int end, String str) { super.replace(start, end, str); return this; } // 这个就是插入操作啦,第一位是告诉哦要插入的位置,后面就是根据不同类型做的一些操作,例如char[]可以告知你想要插入这个数组中的起止位置, // 有很多重载方法,就不一一贴出了 @Override public java.lang.StringBuilder insert(int index, char[] str, int offset, int len) { super.insert(index, str, offset, len); return this; } @Override public java.lang.StringBuilder insert(int offset, Object obj) { super.insert(offset, obj); return this; } ... // 获取指定字符串的 @Override public int indexOf(String str) { return super.indexOf(str); } // 只不过是多了个起始位置,获取下表 @Override public int indexOf(String str, int fromIndex) { return super.indexOf(str, fromIndex); } // 获取指定字符串的最后一个下表 @Override public int lastIndexOf(String str) { return super.lastIndexOf(str); } // 增加了一个位置 @Override public int lastIndexOf(String str, int fromIndex) { return super.lastIndexOf(str, fromIndex); } // 反转 @Override public java.lang.StringBuilder reverse() { super.reverse(); return this; } // 获取字符串 @Override @HotSpotIntrinsicCandidate public String toString() { // Create a copy, don't share the array return isLatin1() ? StringLatin1.newString(value, 0, count) : StringUTF16.newString(value, 0, count); } }
接下来,我们来具体时间使用一下这个
public class HelloWorld { public static void main(String[] args) { StringBuilder s1 = new StringBuilder(); StringBuilder s2 = new StringBuilder(1024); StringBuilder s3 = new StringBuilder("love"); System.out.println(s1.toString()); // System.out.println(s2.toString()); // System.out.println(s3.toString()); // love 这个为什么会有呢,可以看当时提到的父类,他在穿字符串初始化时,实际上时判断字符串长度与integer的最大长度减16进行对比,然后在定义长度,并将值给他 s1.append(1); s1.append(true); s2.append(String.valueOf(1)); s3.append(new char[]{'1'}); s3.append(new char[]{'1', '2', '3', '4'}, 1, 3); // 开始位置,增加几位,注意这两个数之和,不要超过数组的长度 System.out.println(s1.toString()); // 1true System.out.println(s2.toString()); // 1 System.out.println(s3.toString()); // love1234 s1.insert(1, "2"); s2.insert(0, 10.58f); s3.insert(4, new char[]{'a'}); System.out.println(s1.toString()); // 12true System.out.println(s2.toString()); // 10.581 System.out.println(s3.toString()); // lovea1234 System.out.println(s3.indexOf("1")); // 5 System.out.println(s3.lastIndexOf("4", 3)); // -1 s1.replace(0, 1, "3"); // 32true System.out.println(s1.toString()); // 3 // s1.delete(1,100); // 超出范围就会报错 s1.delete(1, 3); System.out.println(s1.toString()); // 3rue 删除顾头不顾维 // s2.deleteCharAt(1222); // 超出范围就会报错 s2.deleteCharAt(1); System.out.println(s2.toString()); // 1.581 } }
对于普通字符串的➕操作,编译器在编译时会帮助我们转化一个类,并在运行时帮助我们将其转化为StringBuilder,因此不需要考虑太多.
对于我们常用的基本数据类型,不能赋值为null,那这些基本的数据类型对应的引用类型是哪些呢?
基本类型 | 对应的引用类型 |
---|---|
boolean | java.lang.Boolean |
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
char | java.lang.Character |
如上述所说,都有对应引用类型,我们可以对这些类型之间进行相互转化
public class HelloWorld { public static void main(String[] args) { int n = 10; Integer i = new Integer(n); // 这种做法最不推荐,因为这样会实例化然后在做, Integer.valueOf(n) 有点浪费资源 Integer i2 = Integer.valueOf(n); // 因为Integer与int之间是自动封箱的,这个可以不用写,但如果需要写的话,推荐这样写,这样效率会高一些 Integer i3 = n; int m = i2; System.out.println(i); //10 System.out.println(i2); // 10 System.out.println(i3); // 10 System.out.println(m); //10 System.out.println(Integer.parseInt("1234")); // 1234 字符串转换 } }
javabean:
javabean一般就是用过private来声明属性(我习惯叫属性,一般叫字段),然后通过public定义的方法来进行读写,并且格式遵循:读方法:get属性名,写方法:set方法名,一般情况下,我们在类中声明了private,可以在ideal中邮件直接创建读写方法,如果这个类中只包含读方法,那就说明这个类是只读类。
为了跟上潮流,后续我就把这个属性改成叫字段啦
另外,java提供了一个包,帮助我们枚举所有的字段跟方法,叫Introspector,就是枚举,这个感觉很实用,以后我们在进行搭建框架的时候,可以封装一个类来进行对应传入实例的调用,这个再次不进行演示了。
import java.beans.Introspector; import java.beans.*; class Person{ private String name; private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public class HelloWorld { public static void main(String[] args) throws Exception { BeanInfo b = Introspector.getBeanInfo(Person.class); for(PropertyDescriptor n : b.getPropertyDescriptors()){ System.out.println(n.getName()); System.out.println(n.getReadMethod()); System.out.println(n.getWriteMethod()); } // age //public int Person.getAge() //public void Person.setAge(int) //class //public final native java.lang.Class java.lang.Object.getClass() //null //name //public java.lang.String Person.getName() //public void Person.setName(java.lang.String) System.out.println(new Person().getClass()); // class Person } }
既然说到了枚举,那就不得不提及一下java里面的枚举类,关键字定义为enum,例如enum Weekend,他最终被被编译器翻译成finnal class Weekend extends Enum,因此我们定义的枚举类是不可继承的,
枚举很实用跟swith搭配
enum Weekend{ // 这个括号中的内容可以不写,如果不写那么那个那个初始化也就不用xie Mon(1,"周一"), Tus(2,"周二"), Wen(3,"周三"), Thi(4,"周四"), Fri(5,"周五"), Sat(6,"周六"), Sun(7,"周日"); public final int num; private final String str; private Weekend(int n, String s){ this.num = n; this.str = s; } @Override public String toString(){ return this.str; } } public class HelloWorld { public static void main(String[] args) throws Exception { Weekend mon = Weekend.Mon; System.out.println(mon.num); // 1 这个是我们自己定义的 System.out.println(mon.toString()); // 周一 定义的字段 System.out.println(mon.ordinal()); // 0 这个就是下标,也就是顺序,因此一般我们在做这种操作时,尽量不要用这种方法来获取常量值,容易搞乱,比如我把Sun提到最前面,就又是一种结果 System.out.println(mon.name()); // Mon 这个就是常量的字段名 System.out.println(mon.equals(1)); // false 判断是否相等,请使用equals,可以看出,只有weekend.mon是相同的 System.out.println(mon.equals("周一")); // false System.out.println(mon.equals("Mon")); // false System.out.println(mon.equals(0)); // false System.out.println(mon.equals(Weekend.Mon)); // true switch (mon){ case Sun: case Sat: System.out.println("weekend"); break; case Mon: case Tus: case Wen: case Thi: case Fri: System.out.println("weekday"); break; default: System.out.println("not found"); break; } // weekday } }
java有很多常用的包,下面列举几个
Math:
public class HelloWorld { public static void main(String[] args) throws Exception { System.out.println(Math.abs(-99)); // 99 计算绝对值 System.out.println(Math.max(1, 2)); // 2 计算最大值 System.out.println(Math.min(1, 2)); // 1 计算最小值 System.out.println(Math.pow(10, 2)); // 100 计算10的2次方 System.out.println(Math.sqrt(2)); // 1.4142135623730951 计算指定数的平方 System.out.println(Math.exp(1)); // 2.718281828459045 计算e的几次方 System.out.println(Math.exp(2)); // 7.38905609893065 System.out.println(Math.log(4)); // 1.3862943611198906 计算log的指定数 System.out.println(Math.log10(100)); // 2.0 System.out.println(Math.sin(5)); // -0.9589242746631385 计算sin System.out.println(Math.cos(5)); // 0.28366218546322625 计算 cos System.out.println(Math.tan(4)); // 1.1578212823495775 计算 tan System.out.println(Math.PI); // 3.141592653589793 PI常量,圆周率 System.out.println(Math.E); // 2.718281828459045 e的常量 System.out.println(Math.random()); // 0.4516913402063736 随机返回一个 0 至 1 的数 System.out.println(Math.random()); // 0.4255472992888448 System.out.println(Math.random()); // 0.7124471108227883 } }
Random
import java.util.Random; public class HelloWorld { public static void main(String[] args) throws Exception { Random r = new Random(); Random r1 = new Random(111); System.out.println(r.nextBoolean()); // true 随机获取boolean值 System.out.println(r.nextInt()); // 1659406565 随机获取一个整数 System.out.println(r1.nextInt()); // -1196652709 System.out.println(r.nextFloat()); // 0.5547011 随机获取[0,1]之间的浮点数 System.out.println(r.nextDouble()); // 0.15836726706631754 随机获取[0,1]之间的double System.out.println(r.nextLong()); // -1408936196736804046 随机获取[0,1]之间的long System.out.println(r.nextInt(100)); // 98 随机获取一个从0 至100的整数 System.out.println(r1.nextInt(10)); // 3 随机获取1个从 0 至10 的整数 // random产生的是伪随机数,s每次得到的结构不同,但是s1每次的结果相同,为什么呢,因为我们为s1制定了一个种子,因此产生的序列不同 // 而未被制定中的话,经看源码,根据系统的纳秒来进行初始化seed(种子),因此得到的值不同 // public Random() { // this(seedUniquifier() ^ System.nanoTime()); // } StringBuilder s = new StringBuilder(); StringBuilder s1 = new StringBuilder(); for (int i = 0; i < 10; i++) { s.append(r.nextInt(100)).append(" "); s1.append(r1.nextInt(100)).append(" "); } System.out.println(s.toString()); // 5 84 31 75 83 14 75 80 72 39 System.out.println(s1.toString()); // 57 97 9 20 84 12 97 65 60 34 } }
有伪随机数就有真随机数,加下来看一下安全性较的SecureRandom:
import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; public class HelloWorld { public static void main(String[] args) throws Exception { SecureRandom sr = null; // 不支持初始化种子 try { sr = SecureRandom.getInstanceStrong(); // 获得高强度安全随机数生成器 } catch (NoSuchAlgorithmException e) { sr = new SecureRandom(); // 普通安全随机数生成器 } System.out.println(sr.nextInt()); // -1418568105 System.out.println(sr.nextInt(100)); // 64 byte[] b = new byte[32]; sr.nextBytes(b); System.out.println(Arrays.toString(b)); // [-45, -101, 38, -113, -65, 2, 69, -116, 82, 26, -116, -22, 104, 58, -70, -92, 108, -13, 120, -44, 65, -90, -2, 73, -5, 50, -3, 116, -15, -60, 126, -50] } }