A. 求助,如何判断一个string类型的字符串
首先楼主肯定知道"=="和equals的区别,我这里再说下:
==比的是两个对象的地址。
equals是java.lang.Object类的一个方法,默认跟"=="一样也是比的地址。如果判断对象相等有其他的标准(例如只要值相等就代表相等),那么就需要重写java.lang.Object的equals方法。String类就重写了此方法,只要对象值相等即可。
Java运行时会维护一个String Pool(String池),String Pool与JAVA堆栈是各自独立的。
String池用来存放运行时中产生的各种字符串,并且池中的字符串的内容不重复。
String对象的创建遵循以下几个原则。
原则1:只要使用new关键字来创建对象(String str = new String("123")),则一定会(在堆区或栈区)创建一个新的对象。 我们知道,只要一个对象是New出来的,那JVM肯定会在内存中为此对象分配一个唯一的地址,因此New出的对象跟任意一个对象用“==”判断肯定为false。
原则2:使用直接指定来创建String对象(如String str="123"),则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。
原则3:使用包含变量的表达式来创建对象String(String str = "123"+"456"),则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。
B. java.lang.String的常用的方法
public boolean equals(Object obj)
判断当前字符串与obj的内容是否相同
public boolean equalsIgnoreCase(String str)
判断当前字符串与str的内容是否相同,这个方法不会区分大小写字母的区别
public int length()
返回字符串的长度,即字符的总个数
public String trim()
去掉字符串两端的空白,包括“空格, ,
,
等控制符”
public String substring(int start,int end)
根据开始和结束的位置,返回当前String的子字符串
public String substring(int start)
从开始位置开始到字符串结束,返回子字符串
public char charAt(int index)
返回指定位置的字符
public int indexOf(String str)
返回子字符串在当前字符串的位置,如果当前字符串不包含子字符串就返回-1
public String concat(String str)
返回一个字符串,内容是当前字符串与str连接而成的。
字符串连接可以简化写为String str = str1 + str2;结果与concat方法相同
public boolean startsWith(String str)
判断当前字符串,是否以str开头
public boolean endsWith(String str)
判断当前字符串,是否以str结尾
========================================================
String str = I am + Lingo!;
这样可以获得一个内容为I am Lingo!的字符串,在java里可以通过这种简单的方式实现字符串的连接
。这里需要注意的是,这个过程实际上生成了三个String对象,I am 和Lingo!先被生成,然后用他
们再创建一个String对象str,str的内容是两者的总和。所以,使用+进行字符串连接的时候会很耗费资
源,这个时候就需要使用另一个类StringBuffer,它的内容是可以修改的,实际上jvm内部编译之后,“
用+进行字符串连接”也是用StringBuffer实现的。
String str = I am + Lingo!;
String str = new StringBuffer(I am ).append(Lingo!).toString();
上边两个是等价的。
StringBuffer类还提供了许多便利的方法,对字符串进行操作
public void reverse()
反转字符串
public void append(...)
在字符串最后添加信息
public void insert(int start,...)
在索引位置插入信息
public void delete(int start,int end)
删除指定范围的内容
split与replaceAll方法
public String[] split(String regex)
根据分隔符,把字符串切割成字符串数组
public String replace(String regex,String str)
把字符串中所有与regex匹配的部分都替换成str
regex代表“正则表达式”,如果你并不清楚它的原理,很可能会出现问题。
1,3,4.split(,)返回的结果是{1,3,4}这三个字符串组成的数组
1|3|4.split(|)返回的结果却是{1,|,3,|,4}五个字符串组成的数组
这个问题的原因是由于在“正则表达式”中,“|”是一个有特殊含义的字符,表示“或”,直接使用
split(|)就会把每个字符分开了。如果希望使用|作为分隔符,就需要使用转义字符。
1|3|4.split(\|)返回的结果就是{1,3,4}三个字符串组成的数组了
“|”是正则表达式中代表|的专一字符,但因为在String中“”不能单独出现,还需要进行一次转义
,就变成了“\|”这种形式。
replaceAll(String regex,String str)也是这种情况
C. 已经编译好的jvm指令集如何生成class文件
语言表达的.....说的通俗易懂点,感觉你的问题也不能算问题吧
D. java如果判断一个字符串中是否有乱码
据我所知, 貌似没有这样的解决办法...
从编译器角度来说 , 因为java在得到一个字符串变量的时候, JVM就已经认定它是合法对象了
从业务逻辑上来说 , 什么叫乱码? 有可能是一堆中国人无法正常解读的字符串, 如果是硬性要求的话, 需要参考一些中文的分词器来做了, 例如庖丁解牛.
最后劝您一句, 如果没有硬性要求, 不要继续研究这个了, 没有太大的实际意义.
E. java编译器和JVM有什么区别
java编译器把java源码编译成字节码 (.class文件).
jvm是在运行期将class文件编译成机器码文件.供程序运行.
F. 编译原理中如何用c语言来编写程序判断输入的字符串是否符合文法规则
scanf()有返回值,若返回值是0,则不符合文法规则
一般情况下,scanf()返回值是输入的字符数
G. Java:为什么说这里的字符串值不能在编译时就确定下来
应该是这个意思,编译完成之后:
String s4 = "疯狂Java";
String s5 = s2 + s3;
H. 前的Java的switch语句能判断String 类型吗
在Java7之前,switch只能支持 byte、short、char、int或者其对应的封装类以及Enum类型。在Java7中,呼吁很久的String支持也终于被加上了。
例如,下面是一段switch中使用String的示例代码。
public class Test {
public void test(String str) {
switch(str) {
case "abc":
System.out.println("abc");
break;
case "def":
System.out.println("def");
break;
default:
System.out.println("default");
}
}
}
在switch语句中,String的比较用的是String.equals,因此大家可以放心的使用。
需要注意的是,传给switch的String变量不能为null,同时switch的case子句中使用的字符串也不能为null。
为什么要有这些非null的限制呢?其实,我们只要将这段代码反汇编出来,看一下底层到底是如何实现的,就可以明白了。下面是汇编出来的代码。
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public void test(java.lang.String);
Code:
0: aload_1
1: astore_2
2: iconst_m1
3: istore_3
4: aload_2
5: invokevirtual #2; //Method java/lang/String.hashCode:()I
8: lookupswitch{ //2
96354: 36;
99333: 50;
default: 61 }
36: aload_2
37: ldc #3; //String abc
39: invokevirtual #4; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_3
47: goto 61
50: aload_2
51: ldc #5; //String def
53: invokevirtual #4; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_3
61: iload_3
62: lookupswitch{ //2
0: 88;
1: 99;
default: 110 }
88: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #3; //String abc
93: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 118
99: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #5; //String def
104: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 118
110: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
113: ldc #8; //String default
115: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
118: return
}
估计有些同学懒得看这些汇编,其实把上面的汇编代码用Java写出来就是下面的样子了。
写到这里,大家应该能明白为什么不能用null了吧。
public class Test {
public void test(String str) {
int i = -1;
switch(str.hashCode()) {
case 96354: // "abc".hashCode()
if (str.equals("abc")) {
i = 0;
}
break;
case 99333: // "def".hashCode()
if (str.equals("def")) {
i = 1;
}
break;
default:
break;
}
switch(i) {
case 0:
System.out.println("abc");
break;
case 1:
System.out.println("def");
break;
default:
System.out.println("default");
}
}
}
如果switch传入的null,那么在运行时对一个null对象调用hashCode方法会出现NullPointerException。
如果switch的case写的是null,那么在编译时无法求出hashCode,因此在编译时就会报错了。
switch支持String只是一个语法糖,由javac来负责生成相应的代码。底层的JVM在switch上并没有进行修改。
I. Java:字符串在JVM常量池中是如何存储的呢
首先你要知道jvm常量池也是对象池,它和在堆中的存储没有区别(底层存储都是一样的,只是对象之间的引用有差别)。那为什么要有常量池呢?因为它可以节省时间和空间,当需要一个对象的时候,可以直接从常量池中获取,而不需要重新创建,这样也就节省了时间和空间(常量池判断对象是否存在应该是equals方法)。
除了String外,Java的8种基本类型(Byte, Short, Integer, Long, Character, Boolean, Float, Double)除Float和Double以外,其它六种都实现了常量池。
楼主这么好学,我出个题目给楼主:
Integer i = 127;
Integer j = 127;
System.out.println(i == j);
提示:对象存在常量池
Integer m = 128;
Integer n = 128;
System.out.println(m == n);
提示:对象存在堆内存
J. java高手来啊,字符串相等问题
这个其实很简单,但是实际中这么写代码的人会被人鄙视死的。
先说第一点
String对象是不可变的。String类中每一个看起来会修改String值的方法,实际上的都是创建了一个全
新的String对象。而用于String的+和+=是java中仅有的两个重载过的操作符。而java(1.6)编译器是
通过引入StringBuilder(你可以打开你所写的class文件看字节码,里边肯定会有invokespecial和
invokevirtual这就是初始化init方法了一个StringBuilder对象和调用其append方法,如果不想了解这
么深,括号里的内容可以忽略)来实现的+或者+=的重载,最后通过toString返回其产生的新对象(源代码里是new的)。
然而要注意一点(只针对这个题目),对于一个class来说当其成员变量是String的静态final域时,在类被编译时编译器会进行优化和改进。这里的优化就是String替换.举个例子
public static final String c="c";
public static final String d="d";
public static final String dddccc=d+d+d+c+c+c;
public static void main(String[] args){
String ccd = c+c+d;
}
会优化变成
public static final String c="c";
public static final String d="d";
public static final String dddccc="dddccc";
public static void main(String[] args){
String ccd = "ccd";
}
原因很简单编译器为了提高效率和无效代码。而如果将上述变量(a和b)的初始化话放在构造方法(虽然这里的a,b必须在static域中初始化,但非static在构造方法里)或者static域中进行的话就不能进行替换啦。static域是在类的init方法后执行(至于神马是init方法和有什么特点,你可以看看JVM相关的资料,还有至于为什么编译器可以这么优化,如果楼主对final域比较了解的话就能理解了)。
2。字符串池
这个可以把它理解成是java对字符串的一种缓存机制(虽然实际并非如此),由于字符串操作频繁,
如果没有字符串池的话,会造成大量String对象被频繁的创建和销毁。这对于java这种语言的效率来说
是不可接受的。因此java在内存中会单独开辟一块内存用来存放字符串对象(只能由String类来维护)。程序中出现的字符串常量都是在池中的。比如String a = “ab”,String c =”cd“。而new操作符产生的String对象将不会放在字符串池中。如String cd = new String("cd");是在堆中的(java中所有的对象的存放地)至于为什么,还是那句话:说来话长。
好我可以开始解释了
String ab=a+b;//通过+运算符返回新的String对象
System.out.println(ab=="ab");//"ab"是池中对象,ab没有在池中的对象不一样
结果false 不解释。
String cd=c+d;
System.out.println(cd=="cd");
编译器优化后
String cd="cd';//池中对象
System.out.println(cd=="cd");//跟自身相比肯定相等 true 不解释
String tmp=new String(new char[]{'c','d'});
这里解释一下intern的实现逻辑
如果池中已经有相同的字符串了,直接返回池中字符串,否则将tmp拷贝一份放入池中并返回池中对象
注意这里是拷贝而不是将引用指向池中对象(String是final的)
String t=tmp.intern();// 返回池中的"cd",因为已经存在了cd所以这个返回的对象跟cd没有半毛钱的关系。
System.out.println(cd==t);// 肯定是true不解释
我写了这么多,只是觉得大家对于String这个对象特别的执着,不论是面试还是考试 ,其实你只要不再循环里+或者+=字符串的话其实是没有什么问题。你平时写个 Stirng aaa = "a'+"b"的话编译器是会帮你优化的。无关痛痒。