1. String
字符串是我们常用的引用类型的数据结构,看一下用法:
public classHelloWorld {public static voidmain(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 (charm : 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= newString(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 classStringBuilderextendsAbstractStringBuilderimplements java.io.Serializable, Comparable, CharSequence
{//这个就是初始化,方法重载,如果不穿值默认是16,可不传或者 int String CharSequence, 篇幅较长,省略一下
@HotSpotIntrinsicCandidatepublicStringBuilder() {super(16);
}
@HotSpotIntrinsicCandidatepublic StringBuilder(intcapacity) {super(capacity);
}
...//这个就是方法重写,做比较的,字串穿比较
@Overridepublic intcompareTo(java.lang.StringBuilder another) {return super.compareTo(another);
}//方法重写,这个就是添加操作,当传入的是对象,获取对象的值,然后调用值类型对应的append的方法签名,观察下面的append,发现最后是把this返回去了//这个append可以添加各种类型,源码就不一一贴出来了,可以自己去看
@Overridepublicjava.lang.StringBuilder append(Object obj) {returnappend(String.valueOf(obj));
}
@Override
@HotSpotIntrinsicCandidatepublicjava.lang.StringBuilder append(String str) {super.append(str);return this;
}
...//删除操作。可以看出来,他这个就是告诉起止位置,然后进行删除操作
@Overridepublic java.lang.StringBuilder delete(int start, intend) {super.delete(start, end);return this;
}//删除指定位置
@Overridepublic java.lang.StringBuilder deleteCharAt(intindex) {super.deleteCharAt(index);return this;
}//替换,告诉起止位置,以及字符串
@Overridepublic java.lang.StringBuilder replace(int start, intend, String str) {super.replace(start, end, str);return this;
}//这个就是插入操作啦,第一位是告诉哦要插入的位置,后面就是根据不同类型做的一些操作,例如char[]可以告知你想要插入这个数组中的起止位置,//有很多重载方法,就不一一贴出了
@Overridepublic java.lang.StringBuilder insert(int index, char[] str, intoffset,intlen)
{super.insert(index, str, offset, len);return this;
}
@Overridepublic java.lang.StringBuilder insert(intoffset, Object obj) {super.insert(offset, obj);return this;
}
...//获取指定字符串的
@Overridepublic intindexOf(String str) {return super.indexOf(str);
}//只不过是多了个起始位置,获取下表
@Overridepublic int indexOf(String str, intfromIndex) {return super.indexOf(str, fromIndex);
}//获取指定字符串的最后一个下表
@Overridepublic intlastIndexOf(String str) {return super.lastIndexOf(str);
}//增加了一个位置
@Overridepublic int lastIndexOf(String str, intfromIndex) {return super.lastIndexOf(str, fromIndex);
}//反转
@Overridepublicjava.lang.StringBuilder reverse() {super.reverse();return this;
}//获取字符串
@Override
@HotSpotIntrinsicCandidatepublicString toString() {//Create a copy, don't share the array
return isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value,0, count);
}
}
接下来,我们来具体时间使用一下这个
public classHelloWorld {public static voidmain(String[] args) {
StringBuilder s1= newStringBuilder();
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 classHelloWorld {public static voidmain(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,就是枚举,这个感觉很实用,以后我们在进行搭建框架的时候,可以封装一个类来进行对应传入实例的调用,这个再次不进行演示了。
importjava.beans.Introspector;import java.beans.*;classPerson{privateString name;private intage;public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}
}public classHelloWorld {public static void main(String[] args) throwsException {
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搭配
enumWeekend{//这个括号中的内容可以不写,如果不写那么那个那个初始化也就不用xie
Mon(1,"周一"), Tus(2,"周二"), Wen(3,"周三"), Thi(4,"周四"), Fri(5,"周五"), Sat(6,"周六"), Sun(7,"周日");public final intnum;private finalString str;private Weekend(intn, String s){this.num =n;this.str =s;
}
@OverridepublicString toString(){return this.str;
}
}public classHelloWorld {public static void main(String[] args) throwsException {
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){caseSun:caseSat:
System.out.println("weekend");break;caseMon:caseTus:caseWen:caseThi:caseFri:
System.out.println("weekday");break;default:
System.out.println("not found");break;
}//weekday
}
}
java有很多常用的包,下面列举几个
Math:
public classHelloWorld {public static void main(String[] args) throwsException {
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
importjava.util.Random;public classHelloWorld {public static void main(String[] args) throwsException {
Random r= newRandom();
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 = newStringBuilder();
StringBuilder s1= newStringBuilder();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:
importjava.security.NoSuchAlgorithmException;importjava.security.SecureRandom;importjava.util.Arrays;public classHelloWorld {public static void main(String[] args) throwsException {
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]
}
}