String类代表字符串类,java程序中所有的字符串文字都作为该类的实例,字符串不变,他们的值在创建之后不可被更改。 特点:
类被final修饰,表明不可被继承。类实现了Serializable接口,表明该类可以序列化。类实现了Comparable接口,表明该类可以比较大小。类内部定义了final char[] value,用于存储字符串数据。 1)字面量的方式
String string=“abc”; //生成的对象在方法区的常量池中
2)调用构造器的方式来创建String对象
String string=new String(“abc”); //创建了两个对象
初始化新创建的String对象,使其表示与参数相同的字符序列; 换句话说,新创建的字符串是参数字符串的副本。
1)创建的对象的个数
String s1=“123”; s1=s1+“45”;
对于这两行代码来说,创建了3个字符串对象,即值为“123”,“45”,“122345”。
2)创建的对象的个数
String string=new String(“abc”);
创建了两个对象,一个对象为“abc”存在于常量池中,另一个为String对象,存在于堆中。
3)jvm内存解析
在jvm的规范中,方法区(又称永久区)逻辑上属于堆的一部分,但是实际落地的时候,方法区和堆是分开的。
常量池的位置也随着JDK版本的迭代发生着变化。
JDK1.6及以前:常量池分配在永久代,在方法区中。
JDK1.7:依旧存在,但是已经逐步去永久代的路上,1.7在堆中(heap space)。
JDK1.8及以后:字符串常量池依旧在方法区,此时不叫永久代,叫metadata,元数据。
常见的编码集:UTF-8,GBK,GB2312,ISO-8859-1,ascII
boolean contains(CharSequence s):判断当前字符串是否包含指定的字符串
int indexOf(String str):判断指定字符是否存在,存在的话返回第一次出现的索引位置,未找到返回-1.
int indexOf(String str,int fromIndex):从指定索引处,查找是否存在指定的字符串,存在返回指定索引,不存在就返回-1.
int lastIndexOf(String str):返回最后一次出现该字符串的索引位置。
int lastIndexOf(String str,int fromIndex):从指定的索引位置开始反向搜索,从右往左,返回最后一次出现该字符串的索引位置。
注意:什么情况下,indexOf和lastIndexOf返回值相同?==>存在唯一的指定字符串,或者不存在该字符串。
1)String和基本数据类型,包装类之间的转换
String==>基本数据类型,包装类:调用包装类的静态方法:parseXxx();
基本数据类型,包装类==>String :调用String重载的valueOf()方法.
2)String和char[]之间的转换
String==>char[] :string里面的方法toCharArray()。
char==>String:String的构造器。
面试题:字符串的反转,变成char数组,然后进行反转
4)String和byte[]之间的转换
String==>byte[]:String方法里面的getBytes()==>编码
byte[]>String:String的构造器>解码
String:JDK1.0,不可变字符序列,底层使用char[]来进行存储。
StringBuffer:JDK1.0,可变字符序列,线程安全的(效率低),底层使用char[]来进行存储。
StringBuilder:JDK1.5新增,可变字符序列,线程不安全的(效率高),底层使用char[]来进行存储。
1)String
String str=new String(); //char[] value=new char[0];
String str1=new String(“abc”); //char[] value=new char[]{‘a’,‘b’,‘c’};
2)StringBuffer和StringBuilder
StringBuffer sb1=new StringBuffer();//new char[16]相当于创建了一个char类型数组长度为16。
sb1.append(‘a’); value[0]=‘a’;
sb1.append(‘b’); value[1]=‘a’;
StringBuffer sb1=new StringBuffer(“abc”);//new char[16+abc.length]相当于创建了一个数组长度为16+abc.length。sb.length=3
sb1.append(‘a’); value[abc.length]=‘a’;
sb1.append(‘b’); value[abca.length]=‘a’;
注意:输出数组的长度为实际字符串的长度。
因为StringBuilder底层使用char[ ] value来进行存储数据,当我们进行追加的时候需要对数组的长度进行判断。接下来对源码进行分析。
//追加字符串的方法,调用父类的方法 @Override public StringBuilder append(String str) { //调用父类中的append(); super.append(str); return this; } //父类中的append方法如下 public AbstractStringBuilder append(String str) { //判断添加的字符串是否为空 if (str == null) return appendNull(); int len = str.length(); //确定容量足够(已经使用的字符长度和新添加的字符串的长度) ensureCapacityInternal(count + len); str.getChars(0, len, value, count); //修改字符数 count += len; return this; } //确定容量的方法(参数为已经使用的字符长度和新添加的字符串的长度) private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code //如果长度不够,进行扩容操作 if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } //扩容 private int newCapacity(int minCapacity) { // overflow-conscious code //容量增大一倍且+2 int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; } private int hugeCapacity(int minCapacity) { if (Integer.MAX_VALUE - minCapacity < 0) { // overflow throw new OutOfMemoryError(); } //Integer.MAX_VALUE - 8==0x7fffffff-8 return (minCapacity > MAX_ARRAY_SIZE) ? minCapacity : MAX_ARRAY_SIZE; } 总结:如果要添加的数据底层数组盛不下,那就需要扩容底层数组,默认情况下扩容为原来容量的的2倍加2。如果还不够用,则新的长度为添加的字符串的长度与原字符串的长度和。然后将这个将数组中的数据复制到新的数组中去。
StringBuffer append(XXX) :追加指定的字符串到末尾。
StringBuffer delete(int start,int end) :删除指定位置的内容。[begin,end)
StringBuffer replace(int start,int end,String str) :替换指定位置的内容。
StringBuffer insert(int offset,xxx) :指定位置插入数据。
StringBuffer reverse() :把当前字符序列反转
public int indexOf(String str):返回指定字符串第一次出现的索引位置
public String substring(int start,int end):返回[start,end)的子字符串。
public int length():返回字符串的长度。
public char charAt(int n):返回指定位置的字符串
public void setCharAt(int n,char ch):修改指定位置的字符
1.字符串大写转化为小写,小写转化为大写,删除其中的数字
public static void main(String[] args) { System.out.println(changestr1("asDSSasd qhw 12131 awdq")); System.out.println(changestr2("asDSSasd qhw 12131 awdq")); } public static String changestr1(String str) { StringBuilder builder=new StringBuilder(str); for (int i = 0; i < builder.length(); i++) { if (builder.charAt(i)>='0'&&builder.charAt(i)<='9') { builder.deleteCharAt(i); i--; }else if (builder.charAt(i)>='a'&&builder.charAt(i)<='z') { builder.setCharAt(i, (char)(builder.charAt(i)-('a'-'A'))); }else if (builder.charAt(i)>='A'&&builder.charAt(i)<='Z') { builder.setCharAt(i, (char)(builder.charAt(i)+('a'-'A'))); } } return builder.toString(); } public static String changestr2(String str) { StringBuilder builder=new StringBuilder(str); for (int i = 0; i < builder.length(); i++) { if (Character.isDigit(builder.charAt(i))) { builder.deleteCharAt(i); i--; }else if (Character.isLowerCase(builder.charAt(i))) { builder.setCharAt(i, (char)(builder.charAt(i)-('a'-'A'))); }else if (Character.isUpperCase(builder.charAt(i))) { builder.setCharAt(i, (char)(builder.charAt(i)+('a'-'A'))); } } return builder.toString(); }1.模拟一个trim方法,去除字符串两端的空格。
1.1 trim源码
public String trim() { int len = value.length; int st = 0; char[] val = value; /* avoid getfield opcode */ while ((st < len) && (val[st] <= ' ')) { st++; } while ((st < len) && (val[len - 1] <= ' ')) { len--; } return ((st > 0) || (len < value.length)) ? substring(st, len) : this; }1.2自定义trim( )
public static String getTrim(String oldString){ char[] chars=oldString.toCharArray(); int beginIndex=0; int lastIndex=0; for (int i = 0; i < oldString.length(); i++) { if(chars[i]!=' '){ beginIndex=i; break; } } for (int i = oldString.length()-1; i>=beginIndex; i--) { if(chars[i]!=' '){ lastIndex=i; break; } } return lastIndex>beginIndex?oldString.substring(beginIndex,lastIndex+1):""; } public static String myTrim2(String oldString) { char[] chars = oldString.toCharArray(); int beginIndex = -1; int lastIndex = -1; // 获取第一个非空字符的下标 for (int i = 0; i < oldString.length(); i++) { if (chars[i] != ' ' && beginIndex == -1) { beginIndex = i; } if (chars[oldString.length() - 1 - i] != ' ' && lastIndex == -1) { lastIndex = oldString.length() - 1 - i; } } if (beginIndex == -1) { return ""; } return oldString.substring(beginIndex, lastIndex + 1); }2.将字符串指定索引内的数据进行反转
public static void main(String[] args) { try { //此处要求[beginIndex,endIndex) System.out.println(StringReverse.getReverse("abcdefg",4,6)); //abcdfeg } catch (Exception e) { System.out.println(e.getMessage()); } } /** * @param oldString :待查找的字符串 * @param beginIndex :起始下标 * @param endIndex :结束下标 * @return :反转之后的字符串 * @throws Exception :抛出异常 */ public static String getReverse(String oldString,int beginIndex,int endIndex) throws Exception { if(endIndex<0||beginIndex<0||beginIndex>=oldString.length()-1||endIndex>=oldString.length()){ throw new Exception("输入的下标越界!!"); } if (beginIndex>endIndex){ throw new Exception("输入的下标不合理!!"); } if (beginIndex==endIndex||beginIndex==endIndex+1){ return oldString; } char[] chars = oldString.toCharArray(); char temp=' '; for (int i = beginIndex,j=endIndex-1; i < j ; i++,j--) { temp=chars[i]; chars[i]=chars[j]; chars[j]=temp; } return new String(chars); } //方式2 public static String reverse(String str) { String ss = ""; for (int i = 0; i < str.length(); i++) { ss = str.charAt(i) + ss; } return ss; }3.获取字符串在另一个字符串中出现的次数
public static void main(String[] args) { int count = NumOfString.getNumOfString("abcabcabc", "ca"); if (count == -1 || count == 0) { System.out.println("该字符串不存在"); } else { System.out.println(count); } } /** * @param str1 :字符串 * @param str2 :待查找的字符串 * @return :出现的次数 */ public static int getNumOfString(String str1, String str2) { int num = 0; int i1 = 0; for (int i = 0; i < str1.length(); i = (i1 + str2.length())) { i1 = str1.indexOf(str2, i); if (i1 == -1) { break; } num++; } return num; }4.获取两个字符串中最大的相同字串。比如:str1=“wefweufihellonqdcbhf”;str2=“qwdchello”;
4.1实现方式1
public static void main(String[] args) { String[] maxString = MaxStringSize.getMaxString("hellohello11", "hello123"); System.out.println(Arrays.toString(maxString)); } public static String[] getMaxString(String str1, String str2) { String[] maxString = new String[10]; int count = 0; String minString = ""; //始终要求str1为两个字符串中比较长的串。 if ((str1.length() < str2.length())) { minString = str2; str2 = str1; str1 = minString; } boolean flag = false; //控制拆分的字符串的长度,长度依次递减 for (int i = str2.length(); i > 0; i--) { //对字符串进行遍历 for (int j = 0; j < str2.length() - i; j++) { //判断长的字符串中是否含有中是否拆分的字符串 String max = str2.substring(j, j + i + 1); boolean contains = str1.contains(max); if (contains) { flag = true; maxString[count++] = max; } } if (flag) { break; } } return maxString; }4.2实现方式2
/** * 获取str1和str2中最大长度的字符串。 * 前提,只有一个最大相同字串。 * 解决方式,使用StringBuffer将其进行追加,以,分隔,然后切分为String类型数组。 * @param str1 :字符串1 * @param str2 :字符串2 * @return :最大相同字串 */ public String getMaxSameString(String str1,String str2){ if (str1!=null&&str2!=null){ String maxStr=(str1.length()>=str2.length())?str1:str2; String minStr=(str1.length()<str2.length())?str1:str2; int length=minStr.length(); //公共存在几大轮 for (int i = 0; i < length; i++) { for (int x = 0,y=length-i; y <=length; x++,y++) { //注意此处时前开后闭 String subStr=minStr.substring(x,y); if (maxStr.contains(subStr)){ return subStr; } } } } return null; } @Test public void testGetMaxSameString(){ String str1="abcwerthello1yuiodefabcdef"; String str2="cvhello1bnm"; String maxSameString = getMaxSameString(str1, str2); System.out.println(maxSameString); }5.查找字符串作用指定字符的数量
/** * @Description:1.获取字符串s中出现字符c次数num * @author 龍 date 2020年6月18日下午2:18:03 * @param s * @param c * @return :字符串中出现的指定字符的次数 */ public static int getNumFromString(String s, char c) { int index = -1; int num = 0; int no = 0; for (int i = 0; i < s.length(); i++) { //进行查找指定的字符 index = s.indexOf(c, no); //如果字符不存在,则跳出循环 if (index == -1) { break; } //找到了指定的字符,字符数量以及寻找的下标++。 num++; no = index + 1; } //返回查找到的数目 return num; }6.字符转换:对指定的字符串进行转换 大写转换为小写 小写转换为大写并 删除其中数字
public static String changeStr(String s) { char[] chars = s.toCharArray(); for (int i = 0; i < chars.length; i++) { if (chars[i] >= 'A' && chars[i] <= 'Z') { chars[i] = (char) (chars[i] + 32); } else if (chars[i] >= 'a' && chars[i] <= 'z') { chars[i] = (char) (chars[i] - 32); } } // 利用正则表达式去除数字 return new String(chars).replaceAll("\\d+", ""); } public static String changeStr02(String s) { char[] chars = s.toCharArray(); String ss = ""; for (int i = 0; i < chars.length; i++) { if (chars[i] >= 'A' && chars[i] <= 'Z') { //如果是大写字母,则转化为小写字母 ss += (char) (chars[i] + 32); } else if (chars[i] >= 'a' && chars[i] <= 'z') { ss += (char) (chars[i] - 32); } else if (chars[i] > '9' || chars[i] < '0') { ss += chars[i]; } } return ss; }7.实现compareTo方法
public static int myCompara02(String str1, String str2) { char[] charArray1 = str1.toCharArray(); char[] charArray2 = str2.toCharArray(); int len = Math.min(charArray1.length, charArray2.length); int last = 0; for (int i = 0; i < len; i++) { last = charArray1[i] - charArray2[i]; if (last != 0) { return last; } } return charArray1.length - charArray2.length; }8.传入的字符串格式为xxxx-xx-xx。将日期s对应的日期加10天后的日期。
public static String getDays02(String str) { int firstIndex = str.indexOf('-'); String year = str.substring(0, firstIndex); int secondIndex = str.indexOf('-', firstIndex + 1); String month = str.substring(firstIndex + 1, secondIndex); String date = str.substring(secondIndex + 1); int intDate = parstInt(date); int intMonth = parstInt(month); int intYear = parstInt(year); System.out.println(intYear + "==" + intMonth + "==" + intDate); int days = getDayFromMonth(intYear, intMonth); intDate += 10; if (days < intDate) { intDate -= days; intMonth++; } if (intMonth == 13) { intYear++; intMonth = 1; } String newDate = "" + intYear + "-" + intMonth + "-" + intDate; return newDate; } public static int parstInt(String time) { int n = 0; for (int i = time.length() - 1, k = 1; i >= 0; i--, k *= 10) { // 获取当前位置的字符 char c = time.charAt(i); // 获取当前位置的数 int cInt = c - '0'; n += k * cInt; } return n; } public static int getDayFromMonth(int year, int month) { switch (month) { case 4: case 6: case 9: case 11: return 30; case 2: return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) ? 29 : 28; default: return 31; } }9.获取参数字符串s中所有数字字符组成的最大整数
public static int getInt(String s) { String ss = ""; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) >= '0' && s.charAt(i) <= '9') { ss += s.charAt(i); } } char[] chars = ss.toCharArray(); // 注意循环前缀。 for (int i = 0; i < chars.length - 1; i++) { for (int j = i + 1; j < chars.length; j++) { // 保证是从小到大的顺序,进行排序。 if (chars[j] > chars[i]) { char tmp = chars[i]; chars[i] = chars[j]; chars[j] = tmp; } } } String newStr = new String(chars); return parstInt(newStr); }10.写一个方法 合并参数字符串中的所有叠词。如:“1111abcaabbbcccddd”—>“1abcabcd”
public static String changeStr04(String s) { /** * 定义一个变量ss来保存不同的字符 如果是第一个字符,则直接添加到ss中 如果不是第一个字符串,和前一个字符进行比较 */ String ss = ""; for (int i = 0; i < s.length(); i++) { if (i == 0) { ss += s.charAt(i); } else { if (s.charAt(i) != s.charAt(i - 1)) { ss += s.charAt(i); } } } return ss; }11.打印参数字符串中数字字符,字母字符和其他字符出现的次数
public static void showAscll(String str) { int numCount = 0; int enCount = 0; int otherCount = 0; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c >= '0' && c <= '9') { numCount++; } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { enCount++; } else { otherCount++; } } System.out.println("数字的个数为:" + numCount + ",字母的个数为:" + enCount + ",其他字符的个数为:" + otherCount); }12.提取数字中的数字到数组中去
public static void showArryFromStr(String str) { String[] nums = new String[10]; String ss = ""; int index = 0; for (int i = 0; i < str.length(); i++) { // 如果是数字则进行保存 if (str.charAt(i) >= '0' && str.charAt(i) <= '9') { ss += str.charAt(i); } else { if (!"".equals(ss)) { nums[index] = ss; index++; ss = ""; } } } if (!"".equals(ss)) { nums[index] = ss; index++; ss = ""; } System.out.println(Arrays.toString(nums)); } public static void getArr(String str) { //遍历字符串把其中所有非数组字符替换为- for (int i = 0; i < str.length(); i++) { char c=str.charAt(i); if (c>'9'||c<'0') { str=str.replace(c, '-'); } } String[] arrs=str.split("-"); //[123, , , 123, , , , 98, , , , , , 876] System.out.println(Arrays.toString(arrs)); int len=0; for (int i = 0; i < arrs.length; i++) { len+=arrs[i].isEmpty()?0:1; } String[] strArr=new String[len]; int index=0; for (int i = 0; i < arrs.length; i++) { if (!arrs[i].isEmpty()) { strArr[index]=arrs[i]; index++; } } System.out.println(Arrays.toString(strArr)); } public static void getArr02(String str) { //遍历字符串把其中所有非数组字符替换为, String ss=""; for (int i = 0; i < str.length(); i++) { char c=str.charAt(i); if (c<'9'&&c>'0') { ss+=c; }else { if (ss!=""&&!ss.endsWith(",")) { ss+=','; } } } String[] strArr=ss.split(","); System.out.println(Arrays.toString(strArr)); }13.一个任意的四位正整数。将数字重新组合成一个最大的数和最小的数相减,重复这个过程,最多七步,必得6174。即:7641-1467=6174。将永远出不来。 求证:所有四位数数字(全相同的除外),均能得到6174。输出掉进黑洞的步数。
public static void darkPool() { for (int i = 1000; i < 10000; i++) { boolean flag = false; int temp = i; for (int j = 0; j < 7; j++) { temp = getMax(temp) - getMin(temp); if (temp == 6174) { System.out.println(i+"调入黑洞,运行了"+(j+1)+"次。"); flag = true; break; } } if (!flag) { System.out.println(i+"未掉入黑洞"); } } } public static int getMax(int k) { int[] nums = getArray(k); // 注意循环前缀。 for (int i = 0; i < nums.length - 1; i++) { for (int j = i + 1; j < nums.length; j++) { // 保证是从小到大的顺序,进行排序。 if (nums[j] > nums[i]) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } } } int max = nums[0] * 1000 + nums[1] * 100 + nums[2] * 10 + nums[3]; return max; } public static int getMin(int k) { int[] nums = getArray(k); // 注意循环前缀。 for (int i = 0; i < nums.length - 1; i++) { for (int j = i + 1; j < nums.length; j++) { // 保证是从小到大的顺序,进行排序。 if (nums[j] > nums[i]) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } } } int min = nums[3] * 1000 + nums[2] * 100 + nums[1] * 10 + nums[0]; return min; } public static int[] getArray(int i) { int num1 = i % 10; int num2 = i / 10 % 10; int num3 = i / 100 % 10; int num4 = i / 1000; int[] nums = new int[] { num1, num2, num3, num4 }; return nums; } 很多方法都过时了,推荐使用日历类Calendar来进行代替。
Data类的API不易于国际化,该类是为了对日期Date类进行格式化和解析,位于java.text.SimpleDateFormat。
年月日星期时分秒yMdEHms 所述Calendar类是一个抽象类,可以为在某一特定时刻和一组之间的转换的方法[calendar fields]如YEAR , MONTH ,DAY_OF_MONTH ,HOUR 等等,以及用于操纵该日历字段,如获取的日期下个星期。 时间上的瞬间可以用毫秒值表示,该值是从1970年1月1日00:00 00:00.000 GMT(Gregorian)的Epoch的偏移量
可变性:像日期和时间这样的类应该是不可变的。
偏移性:Date中的年份是从1900年开始的,月份是从0开始的。
Date date1 = new Date(2020, 10, 1);
System.out.println(date1); //Mon Nov 01 00:00:00 CST 3920
格式化:格式化只对Date有用,Calendar则不行。
也不是线程安全的,也不能处理闰秒等。
java8吸收了joda-Time的精华,新的java.time中包括所有关于本地日期(LocalDate),本地时间(LocalTime),本地日期时间(LocalDateTime),时区(ZonedDateTime)和持续时间(Duration)的类。Date类新增了toInstant( )用于将Date转换成新的表示形式。这些新增的本地化时间日期API大大的简化了日期时间和本地化的管理。
instant:时间线上的一个瞬时点,可能被用来记录应用程序中的事件时间戳。对于人来说年月日时分秒,对于机器来说时间线中一个点就是一个很大的数,有利于计算的处理。UNIX中这个数从1970年开始(utc),以秒为单位,在java中以毫秒为单位。java.time包是基于纳秒计算的,所以instant可以精确到纳秒。
常见的 时间标准:
UTC:世界标准时间GMT:格林尼治时间==>英国CST:北京时间。UTC+8 对时间进行本土化设置
在java中涉及到数组对象的排序问题
说明:java中的对象,正常情况下,只能进行比较:==或者!=,不能使用>或者<,但是在实际的开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小,如何实现?
String,包装类等实现了Comparable接口,重写compareTo()方法,给出了比较两个对象的大小。
重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数。
如果当前对象this小于形参对象obj,则返回负整数。
如果当前对象this等于形参对现象obj,则返回0。
说明:对于自定义类进行排序,自定义类需要实现Comparable接口,若不实现Comparable接口,会报异常:java.lang.ClassCastException: com.atguigu.comparejava.Goods cannot be cast to java.lang.Comparable
自定义类代码compareTo方法实现
class Goods implements Comparable { private String name; private double price; public Goods() { } public Goods(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } /** * 指明该类比较大小的方式:先按照价格从低到高,然后按照产品名称从低到高。 * * @param o:待比较的对象 * @return :结果。正数说明this大,负数说明obj大,o则相等 */ @Override public int compareTo(Object o) { if (o instanceof Goods) { Goods goods = (Goods) o; if (this.price > goods.price) { return 1; } else if (this.price < goods.price) { return -1; } else { //return 0; return this.name.compareTo(goods.name); } } throw new RuntimeException("你输入的商品类型不对!"); } @Override public String toString() { return "Goods{" + "name='" + name + '\'' + ", price=" + price + '}'; } } @Test public void testCompareGoods() { Goods[] goods = new Goods[4]; goods[0] = new Goods("lenovo", 34); goods[1] = new Goods("xiaomi", 50); goods[2] = new Goods("dell", 50); goods[3] = new Goods("huawei", 50); Arrays.sort(goods); System.out.println(Arrays.toString(goods)); } 1)排序:当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用Comparator的对象来排序。
2)实现compare(Object o1,Object o2)方法,比较o1,o2的大小:如果返回值是正数则o1>o2;负数则o1<o2;0则相等。
简单使用
@Test public void testCompareGoods02() { Goods[] goods = new Goods[5]; goods[0] = new Goods("lenovo", 34); goods[1] = new Goods("xiaomi", 50); goods[2] = new Goods("dell", 50); goods[3] = new Goods("huawei", 50); goods[3] = new Goods("huawei", 70); //产品名称从低到高,价格从高到低 Arrays.sort(goods, new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Goods && o2 instanceof Goods) { Goods g1 = (Goods) o1; Goods g2 = (Goods) o2; if (g1.getName().equals(g2.getName())) { return -Double.compare(g1.getPrice(), g2.getPrice()); } else { return g1.getName().compareTo(g2.getName()); } } return 0; } }); System.out.println(Arrays.toString(goods)); } System类代表系统,是系统级的属性和控制方法都放置到该类的内部,位于java.lang包。
特点:
该类的构造器是private的,所以无法创建该类的对象,也无法实例化该类。其内部的成员变量和成员方法都是static的,所以也很方便的进行调用。常见如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Odh6wlCw-1593748287805)(E:\note\p15194420545@163.com\85fc1a6a8e524d29ab3bbb8a1c5c734c\clipboard.png)]
位于java.lang包,提供了一系列静态方法用于科学计算,其方法的参数和返回值类型一般为double型。
Integer类作为int的包装类,能存储的最大整型值为2^31 -1,Long类也是有限的,最大为2^63 -1。如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。因此BigInteger应运而生。
java.math包的BigInteger可以表示不可变的任意长度的整数。BigInteger提供所有Java的基本整数操作符的对应物,并提供 java.lang.Math的所有相关方法。另外,BigInteger还提供以下运算:模算术、GCD计算、质数测试、素数生成,位操作以及一些其他操作。
一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中到要求数字精度比较高,故用到java.math.BigDecimal类 。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
包装类(封装类):针对八种基本数据类型定义相应的引用数据类型–包装类(封装类)
基本数据类型包装类byteByteshortShortintIntegerlongLongbooleanBooleancharCharacterfloatFloatdoubleDouble基本数据类型–>包装类:调用包装类的构造器
包装类–>基本数据类型:调用包装类中xxxValue()。
基本数据类型,包装类–>String类型:①使用拼接符号②String.valueOf()
String类型–>基本数据类型,包装类:包装类.parseXxx();
自动装箱:不需要使用构造器进行封装。
int num=10;
Integer in1=num;
自动拆箱:自动转化为int类型
Integer in2=new Integer(10);
int num2=in2;
注:如果Boolean输入不是一个标准的“true”,则都认为是false。如果数字类型字符串的转换为包装类的时候,有可能报成NumberFormatException。
1.自动装箱面试1
public void wrapperTest(){ Integer a = new Integer(3); Integer b=3; int c=3; Integer d=new Integer(3); //false:不同的对象引用 System.out.println(a==b); //true:a进行自动拆箱 System.out.println(a==c); //true:b进行自动拆箱 System.out.println(b==c); //false:不同的对象引用 System.out.println(a==d); Integer f1=100,f2=100,f3=200,f4=200; //true:没有超出缓存范围,使用了同一个引用 System.out.println(f1==f2); //false:超出了内部缓存的范围,使用了不同的引用 System.out.println(f3==f4); } 解析:首先需要注意的是 f1、f2、f3、f4 四个变量都是 Integer 对象引用,所以下面的==运算比较的不是值而是引用。装箱的本质是什么呢?当我们给一个 Integer 对象赋一个 int 值的时候,会调用 Integer 类的静态方法 valueOf,如果看看 valueOf 的源代码就知道发生了什么。 ```java //源码 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } /** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } ```java 简单的说,如果整型字面量的值在-128 到 127 之间,那么不会 new 新的 Integer 对象,而是直接引用同一个对象 semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }简单的说,如果整型字面量的值在-128 到 127 之间,那么不会 new 新的 Integer 对象,而是直接引用常量池 中的 Integer 对象,所以上面的面试题中 f1 == f2 的结果是 true,而 f3==f4 的结果是 false。