//System.out.print(stringArr[i]);
//System.out.print(stringArr[0]);
if('J'==stringArr[i]){
System.out.print(i);
}
}
}
}
1.自己设计一个坐标类,能提供以下方法如求当前坐标和其他坐标之间的距离等方法,要求所有变量为私有变量,并提供两个构造函数。
publicclassXYdistance{
privateintx;
privateinty;
XYdistance(){
setX(0);
setY(0);
}
publicvoidsetX(intx){
this.x=x;
}
publicintgetX(){
returnx;
}
publicvoidsetY(inty){
this.y=y;
}
publicintgetY(){
returny;
}
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
XYdistancem_1=newXYdistance();
m_1.setX(10);
m_1.setY(10);
XYdistancem_2=newXYdistance();
doubledistance=(m_1.getX()-m_2.getX())*(m_1.getX()-m_2.getX())+(m_1.getY()-m_2.getY())*(m_1.getY()-m_2.getY());
doubleresult=Math.sqrt(distance);
System.out.println(result);
}
}
编写使用静态变量统计一个类产生的实例对象的个数的程序?
publicclassStatic{
privatestaticintnumber;
publicStatic(){
//number=number+1;
++number;
//System.out.println(++number);
}
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
newStatic();
//m_1.Static();
System.out.println(Static.number);
}
}
创建string对象过程的内存分配:
常量池(ConstantPool):
指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。
JVM虚拟机为每个被装载的类型维护一个常量池。
常量池就是该类型所用到常量的一个有序集和,包括直接常量(String,Integer和Floatingpoint常量)和对其他类型,字段和方法的符号引用。
对于String常量,它的值是在常量池中的。
而JVM中的常量池在内存当中是以表的形式存在的,对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:
该表只存储文字字符串值,不存储符号引用。
1、Strings="abc";
创建过程分析:
在class文件被JVM装载到内存中,JVM会创建一块StringPool(String缓冲池)。
当执行Strings=“abc”;时,JVM首先在StringPool中查看是否存在字符串对象“abc”(如何查看呢?
用equals()方法判断),如果已存在该对象,则不用创建新的字符串对象“abc”,而直接使用StringPool中已存在的对象“abc”,然后将引用s指向该对象;如果不存在该对象,则先在StringPool中创建一个新的字符串对象“abc”,然后将引用s指向StringPool中创建的新对象。
注意:
使用“字符串常量”引号创建的字符串对象时,在编译期就已经确定将该对象存储到StringPool中了。
因此,Strings=“abc”只会在编译期,在StringPool中创建一个对象。
例如:
Java代码
1.String s1 = "abc";
2.String s2 = "abc";
3.System.out.println(s1 == s2);//true
结果说明:
JVM创建了两个引用str1和str2,但在StringPool中只创建了一个对象,而且两个引用都指向了同一个对象。
2、Strings=newString("abc");
创建过程分析:
当执行Strings=newString(“abc”);时,JVM首先在StringPool中查看是否存在字符串对象“abc”,如果不存在该对象,则先在StringPool中创建一个新的字符串对象“abc”,然后执行newString(“abc”)构造方法,在Heap里又创建一个新的字符串对象“abc”(new出来的对象都放在Heap里面),并将引用s指向Heap中创建的新对象;如果已存在该对象,则不用创建新的字符串对象“abc”,而直接使用StringPool中已存在的对象“abc”,然后执行newString(“abc”)构造方法,在Heap里又创建一个新的字符串对象“abc”,并将引用s指向Heap中创建的新对象。
注意:
使用newString(“”)创建的字符串对象时,会在运行期创建新对象存储到Heap中。
因此,newString(“abc”)创建字符串对象时,会创建2个对象,编译期在StringPool中创建一个,运行时Heap中创建一个。
这里使用了
Java代码
1.public String(String original)
这个构造方法,作用:
初始化一个新创建的String对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。
由于Sring类是不可变的,因而不必使用该构造方法,除非需要original的显式副本。
例如:
Java代码
1.String s1 = new String("abc");
2.String s2 = new String("abc");
3.System.out.println(s1 == s2);//false
结果说明:
只要是用new()来新建对象的,都会在堆(Heap)中创建,而且其字符串是单独存值的,即使与StringPool中的数据相同,也不会与StringPool中的数据共享。
例程1:
Java代码
1.String s1 = "abcdef";
2.String s2 = "abcdef";
3.String s3 = "abc"+"def";//编译期自动优化为String s3 = "abcdef";
4.System.out.println(s1 == s2);
5.System.out.println(s1 == s3);
6.System.out.println(s2 == s3);
运行结果:
true
true
true
结果说明:
字符串常量生成的字符串对象在StringPool中只有一个拷贝,且它是在编译期就被确定了,所以“s1==s2”;“abc”和“def”都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己也肯定是字符串常量(它在编译期就被解析为一个字符串对象了,即class文件中就已经存在“abcdef”),所以在字符串生成字符串对象时,s3也是StringPool中“abcdef”的一个引用。
故JVM对于字符串常量的"+"号连接,在程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值。
例程2:
Java代码
1.String s1 = "abc";
2.String s2 = "def";
3.String s3 = "abcdef";
4.String s4 = "abc"+"def";
5.String s5 = s1 + "def";
6.String s6 = "abc"+s2;
7.String s7 = s1 + s2;
8.System.out.println(s3 == s4);
9.System.out.println(s3 == s5);
10.System.out.println(s3 == s6);
11.System.out.println(s3 == s7);
运行结果如下:
true
false
false
false
结果说明:
JVM对于有字符串引用存在的字符串"+"连接中,而引用的值在程序编译期是无法确定的,即s1+“def”无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给s5。
例程3:
Java代码
1.final String s1 = "abc";
2.String s2 = "def";
3.String s3 = "abcdef";
4.String s4 = "abc"+"def";
5.String s5 = s1 + "def";
6.String s6 = "abc"+s2;
7.String s7 = s1 + s2;
8.System.out.println(s3 == s4);
9.System.out.println(s3 == s5);
10.System.out.println(s3 == s6);
11.System.out.println(s3 == s7);
运行结果如下:
true
true
false
false
例程4:
Java代码
1.final String s1 = "abc";
2.final String s2 = "def";
3.String s3 = "abcdef";
4.String s4 = "abc"+"def";
5.String s5 = s1 + "def";
6.String s6 = "abc"+s2;
7.String s7 = s1 + s2;
8.System.out.println(s3 == s4);
9.System.out.println(s3 == s5);
10.System.out.println(s3 == s6);
11.System.out.println(s3 == s7);
运行结果如下:
true
true
true
true
结果说明:
例程3和例程4与例程2的区别是,例程3在字符串s1前加了final修饰,例程4在字符串s1和s2前都加了final修饰。
对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。
所以此时的s1+“def”和"abc"+"def"效果是一样的。
接着后面两个含引用的字符串连接,JVM会进行相同的处理。
故上面程序后面三个的结果为true。
例程5:
Java代码
1.public static void main(String args[]){
2. String s1 = "abc";
3. final String s2 = getDef();
4. String s3 = "abcdef";
5. String s4 = "abc"+s2;
6. String s5 = s1 + s2;
7. System.out.println(s3 == s4);
8. System.out.println(s3 == s5);
9.}
Java代码
1.private static String getDef(){
2. return "def";
3.}
程序运行结果如下:
false
false
结果说明:
JVM对于方法调用给字符串引用赋值的情况,引用指向字符串的值在编译期是无法确定的,只有在程序运行调用方法后,将方法的返回值“def”和“abc”动态连接并分配新地址赋值给s4,所以上述程序的结果都为false。
通过以上的例子可知:
Java代码
1.String s = "a" + "b" + "c";
等价于:
Java代码
1.String s = "abc";
编译期,直接优化,进行常量连接。
对于:
Java代码
1.String a = "a";
2.String b = "b";
3.String c = "c";
4.String s = a + b + c;
就不等价于:
等价于:
Java代码
1.String s = "abc";
最终结果等于:
Java代码
1.StringBuilder builder = new StringBuilder ();
2.builder.append(a);
3.builder.append(b);
4.builder.append(c);
5.String s = builder.toString();
去看StringBuilder的toString()方法:
Java代码
1.public String toString() {
2.// Create a copy, don't share the array
3.return new String(value, 0, count);
4.}
可以发现是通过newString(..)返回了一个String对象,也就是说在堆中创建了对象。
这时候会不会在池中出现"abc"这个对象呢?
(question还没解决)
生成Strings的过程中,编译器使用sb执行的过程:
创建一个StringBuffer对象,使用append()向此StringBuffer对象直接添加新的字符串(而不是每次制作一个新的副本)。
对于Stringc="c";Strings="a"+"b"+c;,编译器将会先将"a"+"b"作为编译时常量,优化生成成字面常量"ab",然后生成一个StringBuilder对象,接着调用两次append()方法,即:
Strings=newBuilder().append("ab").append(c).toString();
对于Stringa="a";Strings=a+"b"+"c";,编译器分析a为引用变量,后面的"b"+"c"就不会作为编译时常量来运算了。
相当于执行:
Strings=newBuilder().append(a).append("b").append("c").toString();
对于Stringb="b";Strings="a"+b+"c";],这种形式的就没办法优化了,直接生成StringBuilder对象,然后调用三次append()方法,即:
Strings=newBuilder().append("a").append(b).append("c").toString();
接着,我们再看以下代码:
Java代码
1.String str1 = "abc";//是字符串常量,它在编译期被确定,放在常量池中(共享内容值)
2.//new String()创建的字符串不放入常量池中
3.String str2 =new String("abc");//不是字符串常量,不在编译期确定(不共享内容值)
Java代码
1.String str1 = new String("abc");
2.String str2 = "abc";
3.System.out.println(str1==str2); //false
创建了两个引用。
创建了两个对象。
两个引用分别指向不同的两个对象。
Java代码
1.String str1 = "abc";
2.String str2 = new String("abc");
3.System.out.println(str1==str2); //false
创建了两个引用。
创建了两个对象。
两个引用分别指向不同的两个对象。
接下来我们再来看看intern()方法,它的定义如下:
Java代码
1.public native String intern();
这是一个本地方法。
在调用这个方法时,JAVA虚拟机首先检查StringPool中是否已经存在与该对象值相等对象存在,如果有则返回字符串池中对象的引用;如果没有,则先在StringPool中创建一个相同值的String对象,然后再