final关键字(最终)
final修饰的类无法被继承.
final修饰的方法无法被覆盖.
final修饰的局部变量,一旦赋值,不可再改变.
class A{
public void m1(){
//声明
final int i;
//第一次赋值
i = 100;
//不能重新赋值
i = 1200;
}}
final修饰的成员变量必须“显示的”初始化.
class A{
//final修饰的成员变量必须手动初始化.
final int i = 100;
//成员
final int k;
//Constructor
A(){
k = 200;
}}
//常量.java规范中要求所有的常量“大写”
//常量:值不可再改变的变量.
public static final double PI = 3.14;
深入final
final修饰的引用类型,该引用不可再重新指向其他的java对象。
但是fianl修饰的引用,该引用指向的对象的属性是可以修改的。
public static void main(String[] args){
final Customer c = new Customer("JACK",15);
//c是final的,无法重新赋值。
//c = new Customer("LUCY",20);//Error
c.name = "李四";
c.age = 25;
System.out.println(c.name);
System.out.println(c.age);
}
(String)java.lang.String;是字符串类型。
1.字符串一旦创建不可再改变。"abc"字符串对象一旦创建,不可再改变成"abcd"
2.提升字符串的访问效率:在程序中使用了“缓存”技术。所以在java中所有使用“双引号”括起来
的字符串都会在“字符串常量池”中创建一份。字符串常量池在方法区中被存储。
3.在程序执行过程中,如果程序用到某个字符串,例如"abc",那么程序会在字符串常量池
中去搜索该字符串,如果没有找到则在字符串常量池中新建一个"abc"字符串,如果找到
就直接拿过来用。(字符串常量池是一个缓存区,为了提高访问字符串的效率)
//创建一个"abc"字符串对象,该对象的内存地址,让s1变量保存。
//s1是一个引用,s1指向 "abc" 对象.
String s1 = "abc";
//可以让s1重新指向吗?s1是局部变量,s1前边没有final,所以s1可以重新指向。
//但是"def"字符串本身不可变.
s1 = "def";
String s2 = "Hello"; //在字符串常量池中新建一个"Hello"字符串对象,该对象不可变
String s3 = "Hello"; //从字符串常量池中直接拿来用。
System.out.println(s2==s3); //true
//比较两个字符串是否相等,不能用"=="
String s4 = new String("abc");
String s5 = new String("abc");
System.out.println(s4==s5); //false
//比较两个字符串是否一致,必须使用String类提供的equals方法.
System.out.println(s4.equals(s5)); //true
//以下程序执行结束之后,会在字符串常量池中创建3个字符串对象
//"aaa" "bbb" "aaabbb"
String s6 = "aaa";
String s7 = "bbb";
String s8 = s6 + s7;
字符串对象的区别
1.String s1 = "abc"; 只会在字符串常量池中创建一个"abc"字符串对象.
2.String s2 = new String("hello"); 会在字符串常量池中创建一个"hello"字符串对象,并且会在堆中再创建一个字符串对象。
第二种方式比较浪费内存,常用的是第一种方式。
面试题
//判断以下程序创建了几个对象? 3个
//堆中2个
//方法区字符串常量池中1个.
String s1 = new String("Hello");
String s2 = new String("Hello");
使用String的时候我们应该注意的问题:尽量不要做字符串频繁的拼接操作。
因为字符串一旦创建不可改变,只要频繁拼接,就会在字符串常量池中创建
大量的字符串对象,给垃圾回收带来问题。
String[] ins = {"sport","music","food","sleep"};
//要求将上面的兴趣爱好拼接成一个字符串“sport,music,food,sleep”
String temp = "";
for(int i=0;ins.length; I++){
if(i==ins.length-1){
temp += ins[i];
}else{
temp += ins[i] + ",";
}
}
System.out.println(temp);
字符串常用构造方法
//1.String s1 = "abc";
//2.String s2 = new String("abc");
//3.byte[] bytes = {97,98,99,100};
String s3 = new String(bytes);
System.out.println(s3); //abcd String已经重写了Object中的toString
//4.String s4 = new String(bytes,1,2);
System.out.println(s4); //bc
//5.char[] c1 = {'我','是','中','国','人'};
String s5 = new String(c1);
System.out.println(s5); //我是中国人
//6.String s6 = new String(c1,2,2);
System.out.println(s6); //中国
字符串常用的方法
//1.char charAt(int index);返回指定索引处的char值
String s1 = "我是王勇,是坏人!";
char c1 = s1.charAt(2);System.out.println(c1); //王
//2.boolean endsWith(String endStr);此字符串是否以指定的后缀结束
System.out.println("HelloWorld.java".endsWith("java")); //true
System.out.println("HelloWorld.java".endsWith("txt")); //false
//3. boolean equalsIgnoreCase(String anotherString);将一个Str和另一个str比较,不考虑大小写
System.out.println("abc".equalsIgnoreCase("ABc")); //true
//4.byte[] getBytes();将字符串转换为byte数组
byte[] bytes = "abc".getBytes()
//5.int indexOf(String str);判断此字符串在另一个字符串第一次出现的索引
System.out.println("http://192.168.1.100:8080/oa/login.action?username=jack&pwd=123".indexOf("/oa"));//25
//6.int indexOf(String str, int fromIndex); 判断此字符串在另一个字符串第一次出现的索引,从指定索引开始,
System.out.println("javaoraclec++javavb".indexOf("java",1)); //13
isEmpty()当且仅当length()为0时返回true
//7.int lastIndexOf(String str)返回此字符串在此字符串中最右边出现的索引
System.out.println("javaoraclec++javavb".lastIndexOf("java")); //13
//8.int lastIndexOf(String str, int fromIndex)从指定的索引反向搜索
System.out.println("javaoraclec++javavb".lastIndexOf("java",14)); //13
//9.int length();
System.out.println("abc".length()); //数组是length属性,String是length()方法
//10. String replaceAll(String s1,String s2);替换,把java替换成mysql
System.out.println("javaoraclec++javavb".replaceAll("java","mysql")); //这个程序是4个字符串//mysqloraclec++mysqlvb
//11.String[] split(String s);
String myTime = "2008,08,08";
String[] ymd = myTime.split(",");以逗号分隔
for(int i=0;ymd.length;i ++){
System.out.println(imd[I]);
}
//12.boolean startsWith(String s);测试此字符串是否以指定的前缀开始
System.out.println("/system/login.action".startsWith("/")); //true
//13.String substring(int begin);截取字符串
System.out.println("/oa/login.action".substring(3)); // /login.action
//14. String substring(int beginIndex, int endIndex)截取字符串
System.out.println("/oa/login.action".substring(4,9)); //login
//15.char[] toCharArray();将此字符串转换为一个新的字符串数组
char[] c2 = "我是李海波".toCharArray();
//16.转换成大写
System.out.println("Abcdef".toUpperCase());
//17.转换成小写
System.out.println("ABCDEf".toLowerCase());
//18.String trim(); 去掉前面空格和后面空格,但去不掉a后和e前的空格
System.out.print(" a bcd e ".trim());
//19.String valueOf(Object obj);返回新的字符串(类型转换)
Object o = null;
System.out.println(o); //不会,因为并不是直接调用toString方法,String.valueOf(Object)这个方法对空值进行处理了。
System.out.println(String.valueOf(o));
//System.out.println(o.toString()); //会出现空指针
java.lang.StringBuffer;
java.lang.StringBuilder;
1.StringBuffer和StringBuilder是什么?
是一个字符串缓冲区.
2.工作原理
预先在内存中申请一块空间,以容纳字符序列,
如果预留的空间不够用,则进行自动扩容,以
容纳更多字符序列。
3.StringBuffer,StringBuilder 和 String最大的区别?
String是不可变得字符序列,存储字符串常量池中。
StringBuffer底层是一个char数组,但是该char数组是可变的。
并且可以自动扩容。
char中是否可以存储一个中文汉字?
解:char底层存储的是unnicode编码格式的中文,
只要unnicode编码中有的中文汉字,就可以在char中声明
4.StringBuffer和StringBuilder的默认初始化容量是16
5.如何优化StringBuffer和StringBuilder呢?
最好在创建StringBuffer之前,预测StringBuffer的存储字符数量,
然后再创建StringBuffer的时候采用指定初始化容量的方式创建StringBuffer.
为了减少底层数组的拷贝。提高效率。
6.StringBuffer和StringBuilder的区别?
StringBuffer是线程安全的。(可以在多线程的环境下使用不会出现问题.)
StringBuilder是非线程安全的。(在多线程环境下使用可能出现问题.)
//创建字符串缓冲区对象
StringBuffer sb = new StringBuffer(); //16
//可以向StringBuffer中追加字符串.
String[] ins = {"体育","音乐","睡觉","美食"};
//推荐字符串频繁拼接使用StringBuffer或者StringBuilder
for(int i = 0; I<ins.length;i ++){
if(i==ins.length-1){
sb.append(ins[i]);
}else{
sb.append(ins[i]);
sb.append(",");
}
System.out.println(sb);
}