String类相关知识(包含intern方法)及字符串拼接的底层原理和优化

2 篇文章 0 订阅
订阅专栏

1、创建字符串

1.1、方式一:字面量声明

String str1 = "hello,mrz";

这种方式会直接将字符串放到字符串常量池中:

注意:在JDK1.7之后(包括1.7),字符串常量池已经从方法区移动到了堆区

当我们再次通过字面量声明一个内容相同的字符串时,不会新建对象,而是直接指向池中的地址,如下图:
在这里插入图片描述
1.2、方式二:new String()

String str2 = new String("hello,mrz");

使用这种方式创建字符串,要分两种情况:

  1. 如果字符串常量池中已经存在了相同内容的字符串对象,只创建一个对象(比如在new之前已经用字面量声明的方法创建了一个相同内容的字符串)

    解释:

    1、"abc"是字符串常量,应该在常量池中创建,JVM在常量池中检查发现已经存在有相同内容的字符串,所以不再创建

    2、遇到new关键字,会在堆中创建一个String对象,返回给str2

在这里插入图片描述
2. 如果字符串常量池中不存在相同内容的常量

1、首先在字符串常量池创建一个"hello,mrz"对象

2、遇到new关键字,在堆中创建一个字符串对象,返回给str2

在这里插入图片描述
1.3、比较以上两种方式可以得到:

1、通过字面量声明的方式最多创建一个对象,最少不创建对象

  • 如果常量池中没有,创建一个对象
  • 如果常量池中已经存在,不创建对象,直接引用

2、通过new String()方式最少创建一个对象,最多创建两个对象

  • 如果常量池中没有,在常量池中创建一个对象,在堆中创建一个对象
  • 如果常量池中已经存在,则只会在堆中创建一个对象
  • 绝对会在堆中创建一个字符串对象,常量池中可能创建可能不创建

1.4、扩展

Strin str = new String(“a”) + new String(“b”) 创建了几个对象?

一共创建了5个对象

解释:

在常量池中创建了2个字符串对象:a"字符串对象,"b"字符串对象

在堆中创建了三个字符串对象:"a"字符串对象,"b"字符串对象,"ab"字符串对象

注意:拼接是在堆中完成的,这里实际上是使用 StringBuilder.append 来完成字符串的拼接, 所以在堆内存中会存在一个 “ab”, 但是在字符串常量池中没有 “ab” 。如果要入池需要使用后文的intern()方法

2、字符串比较相等

2.1、看以下代码

  1. 例一

    String str1 = "Hello";
    String str2 = "Hello"; 
    System.out.println(str1 == str2); //true
    

    至于例一为什么这为true不再赘述,看1.1内存图便可明白:str1和str2指向字符串常量池中同一个地址,固然相等

  2. 例二

    String str1 = new String("Hello,mrz");
    String str2 = new String("Hello,mrz");
    System.out.println(str1 == str2); //false
    

    在这里插入图片描述
    解释:new关键字都是在堆中开辟内存创建对象的,所以肯定地址肯定不同,也就是为false

    可是我们想要的效果是:“只要两个字符串内容相同,就为true”;怎么办呢?那就要使用equals()方法进行判断了

2.2、equals()方法

记住一句话:

使用 == 比较的是两个引用是否指向同一个地址(“身份”是否相同),比较字符串的内容是否相等要使用equals方法

  1. 所以在2.1-例二中,如果是str1.equals(str2),那么结果就是true

  2. 对于自定义的类,如果要比较两个对象的内容是否相同,一定要重写equals()方法

  3. 假如现在要比较str和"hello"内容是否相等,推荐下面这种写法:

    "hello".equals(str);
    str.equals("hello");
    //第二种可能会NullPointerException,第一种永远不会
    

3、String.intern()

3.1、先来看看intern()方法的介绍:

  1. 在jdk1.7之前

    <1>如果池中有相同内容的字符串,则直接返回池中该字符串的引用(地址)

    <2>如果池中没有相同内容的字符串,则会把堆中这个字符串对象拷贝一份,放入常量池,然后返回池中字符串对象的引用

    1. 在jdk1.7之后(包含1.7)

    <1>如果池中有相同内容的字符串,则直接返回池中该字符串的引用

    <2>如果池中没有,则会把这个字符串对象的的地址复制一份,放入池中,并返回池中的引用(指向堆中的字符串对象)

3.2、可能文字并不好解释清楚,接下来我将通过几个案例演示(以jdk1.7为准)

案例一:

String str1 = new String("hello,mrz");
String str2 = "hello,mrz";
str1.intern();
System.out.println(str1 == str2);//false

在这里插入图片描述
解释:

new String(“hello,mrz”),首先在池中创建一个"hello,mrz"对象,然后在堆中创建了字符串对象引用池中对象,返回堆中对象的引用给str1

str2直接引用池中对象的0x444

str1.intern()入池,JVM检测到池中已有相同内容的字符串,返回池中字符串的引用,但这里没有接收,str1还是指向堆中的对象

所以为false

//上述代码中,如果改成
str1 = str1.intern();
//str1接收到返回值,也指向池中对象,那么就是true

案例二:

String str1 = new String("hello") + new String(",mrz");
String str2 = "hello,mrz";
str1.intern();
System.out.println(str1 == str2);//false

在这里插入图片描述
解释:

执行第一句:new String(“hello”)+new String(“,mrz”)

在堆中创建了"hello"对象、“,mrz"对象,在常量池中创建了"hello"对象和”,mrz"对象

然后A对象(上图中)和B对象进行拼接,在堆中出现了"hello,mrz"对象

此时常量池中有"hello",“,mrz”,堆中有A、B、C三个对象(拼接底层使用的是 StringBuilder.append 来完成的, 所以在堆内存中会存在一个 “hello,mrz”对象, 但是在字符串常量池中没有 “hello,mrz”)

执行第二句:str2=“hello,mrz”

因为池中没有"hello,mrz",所以会在池中创建一个"hello,mrz"对象,返回引用给str2

在这里插入图片描述
执行第三句:str1.intern()

入池,JVM检查发现池中已有相同内容的字符串,则返回池中对象的引用,这里同案例一,也是因为没有接收,所以str1还是指向堆中的对象

所以str1肯定不等于str2

案例三:

但是如果我们调换一下第二、第三句代码的顺序呢?这时候答案就为true了!!!

String str1 = new String("hello") + new String(",mrz");
str1.intern();//调换
String str2 = "hello,mrz";//调换
System.out.println(str1 == str2);//true

解释:

第一句代码执行结果同案例二;

第二句str1.intern()入池

此时第三句代码还未执行,池中还没有"hello,mrz"对象,当JVM检查发现池中没有相同内容对象时,就会把堆中C对象的引用复制一份放到池中,然后返回池中的引用地址(就是C的引用)

第三句执行str2=“hello,mrz”

JVM检查发现池中已经有了,则返回常量池中的引用(即str2也是指向C对象)
在这里插入图片描述
所以str1和str2都是指向C对象,那么就是true了

综上所述:new String(“a”) + new String(“b”)一共创建了5个对象(池中没有"a"和"b"的前提向下),堆中三个,池中两个

案例四:

4、如何理解字符串是不可变的?

4.1、看以下代码

String s1 = "East";
s1 = "South";

s1="South"是直接将s1的内容"East"修改为了"West"吗?

不是!

通过查看String类的源代码可以知道:
在这里插入图片描述
String底层是用了一个private final修饰的字符数组:

  • private修饰,表明外部类是访问不到value数组的,同时子类也无法访问
  • final修饰的内容是不可以被改变的,所以对String来说,一旦初始化,value[]将无法再被修改
  • 但是注意,通过反射可以打破封装,可以修改value[]

有人就会说:String既然不可变,那为什么String类还有很多方法都能操作字符串?

其实String类中的很多方法,如toLowerCase,都不是在原来的字符串上进行操作的,而是重新new了个字符串,返回的是新创建的字符串对象

4.2、为什么要求字符串不可变?

  1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑何时深拷贝字符串的问题了.
  2. 不可变对象是线程安全的.
  3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.

5、字符串拼接优化

5.1、看以下代码:

String str1 = "hellomrz";
String str2 = "hello" + "mrz";
System.out.println(str1 == str2);//true

解释:

第一:在池中创建对象"hello,mrz"

第二:编译器在编译时发现"hello" 和 "mrz"都是字符串,会自动进行拼接成"hellomrz"再存储

第三:拼接后存储时,JVM检测到常量池中已有"hellomrz",所以str2会直接引用常量池中的"hellomrz"

故str1中存的地址和str2相同,所以为true

通过反汇编也可以看出两种方法是相同的:
在这里插入图片描述
5.2、看以下代码:

String s1 = "hellomrz";
String s2 = "hello";
String s3 = s2 + "mrz";
System.out.println(s1 == s3);//false

为什么是false呢?首先我们需要先来了解常量和变量的区别:

简但来说:变量只有在运行时才知道其中存储的内容,而常量是在量是在编译时就已经知道存的多少

这里s2就是个变量,编译器在编译时并不知道s2是多少;所以s3在编译时也就是个变量,拼接时在堆中new一个"hello,mrz"对象,返回给s3;s1引用常量池中的"hello,mrz",两者当然不同

5.3、看以下代码:

String  s1 = "hellomrz";
final String s2 = "hello";
String s3 = s2 + "mrz";
System.out.println(s1 == s3);//true

相比于5.2,这里s2用final修饰,结果就变为了true

首先我们需要了解的是:对于常量,编译器在编译时就会帮我们进行运算!

例如final修饰的两个int变量,进行相加,编译器在编译时就帮我相加了,即在编译时c就已经等于30,具体可以用javap命令反汇编验证:

final int a = 10;
final int b = 20;
int c = a + b;//c=30
Code:
      0: bipush        10//a
      2: istore_1			
      3: bipush        20//b
      5: istore_2			
      6: bipush        30//c	编译时就已经知道c=30了
      8: istore_3	

所以final修饰的s2也是常量!

那么s2 + "mrz"相当于 “hello” + “mrz”,编译时就优化成"hello,mrz"存储;JVM检测到池中已有相同内容的对象,就返回池中对象的引用,所以s1 == s3;

6、StringBuilder和StringBuffer

6.1、StringBuilder和StringBuffer大部分功能都是相同的,两者主要的区别就是StringBuffer是线程安全的,而StringBuilder是非线程安全的;后文以StringBuilder举例,StringBuffer同理

6.2、String和StringBuilder的区别?

String和StringBuilder最大的区别在于:String的内容无法修改,如果改变对象的内容,改变的其实是其引用的指向而已;而StringBuilder的内容可以修改

6.3、String进行拼接的原理是什么?

<1>执行下面的代码:

public static void main(String[] args) {
        String str = "hello";
        for (int i = 0; i < 10; i++) {
            str = str + i;
        }
        System.out.println(str);//hello0123456789
    }

​ <2>使用javap进行反汇编:
在这里插入图片描述
从图中可以看到,String在进行拼接时,首先会构造一个StringBuilder对象,然后调用其append()方法进行拼接,拼接完成后又调用其toString()方法赋值给str,这样str就完成了"一次拼接";

因为使用了for循环,所以第33行时"goto 5",回到第五行重新往下执行,又会重复一遍前面的步骤,直到结束循环退出循环

为了方便理解,这里用java代码来模拟一次拼接的过程:

public static void main(String[] args) {
    String s1 = "hello";
    String s2 = "mrz";
    
    //模拟String str = s1 + s2;
    StringBuilder sb = new Stringbuilder();
    sb.append(s1);
    sb.append(s2);
    String str = sb.toString();//完成s1 拼接 s2
}

综上所述:每拼接一次,都会在底层new一个StringBuilder对象

如果在一个程序中反复需要拼接字符串,那么就会在堆中产生大量的StringBuilder对象,浪费内存

6.4、StringBuilder拼接是什么样的?

<1>执行下面的代码:

public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        for (int i = 0; i < 10; i++) {
            sb.append(i);
        }
        String str = sb.toString();
        System.out.println(str);
    }

<2>javap反汇编:
在这里插入图片描述
可以看到,虽然都是for循环拼接了10次,但是使用String拼接构建了10个StringBuilder对象,而使用StringBuilder拼接只创建了一个StringBuilder对象!!!(在17-32行循环并没有创建新的StringBuilder对象)

综合6.3和6.4可得:如果在程序中经常有拼接操作,我们应该选用StringBuilder,如果需要线程安全的,那应该选用StringBuffer

使用String进行拼接效率太低

7、String类一些方法注意事项

7.1、String类的两种构造方法使用

No方法名类型概述
1String(char[] value)构造以字符数组构建字符串
2String(byte[] bytes)构造以字节数组构建字符串

可以看到,通过char数组或byte数组都可以构建一个新的字符串,那我们怎么选择呢?

回答:

byte[] 是把 数据按照一个字节一个字节的方式处理, 这种方式适合在网络传输, 数据存储这样的场景下使用. 更适合针对二进制数据来操作.

char[] 是把数据按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候

7.2、字符串拆分

No方法名类型概述
1String[] split(String regex)成员方法全部拆分
2String[] split(String regex,int limit)成员方法拆分成limit组
String str = "hello world hello mrz" ; 
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result) { 
 System.out.println(s); 
}
//"hello"	"world"  "hello"	"mrz"
/... 
String[] result = str.split(" ", 3) ; // 按照空格拆分成三组
/...
//输出: "hello"	"world"	 "hello mrz"

拆分是一种常用到的操作,有一些特殊字符作为分隔符需要加上转义才能正常分割

举例:拆分IP地址

String str = "192.168.1.1"; 
String[] result = str.split(".");//错误:可疑的正则表达式
for(String s: result) { 
 System.out.println(s); 
}//什么都没输出

正确的做法如下:

String str = "192.168.1.1"; 
String[] result = str.split("\\.");//第一个'\'是用来转义第二个'\'的,而第二个'\'用来转义'.'
for(String s: result) { 
 System.out.println(s); 
}//"192"  "168"	 "1"	"1"

注意事项:

  1. 字符 " | " , " * " , " + " 作为分隔符时,都得加上转义字符
  2. 如果一个字符串中有多个分隔符,可以用 " | " 作为连字符

举例:多次拆分

String str = "name=xiaoming&age=8" ; 
String[] strings = str.split("&") ; 
for (int i = 0; i < result.length; i++) { 
 String[] tStr = result[i].split("=") ; 
 System.out.println(tStr[0]+" = "+tStr[1]); 
}

以上就是我个人关于String类及相关内容的一些总结。可能不是很全面,也有可能一些内容有错误,欢迎大家指正。

第 12 章 字符串常量池 (String Table)、intern()方法String的内存结构、相关面试题
Guizy
01-16 1123
第 12 章 StringTable 1、String 的基本特性 1.1、String 概述 String 的概述 String:字符串,使用一对 “” 引起来表示 String s1 = "mogublog" ; // 字面量的定义方式 String s2 = new String("moxi"); // new 对象的方式 12 String声明为final的,不可被继承 String实现了Serializable接口:表示字符串是支持序列化的。实现了Compar
【个人学习】JVM(10):字符串常量池(StringTable)、String的内存分配、字符串拼接StringTable的垃圾回收
最新发布
dopapapa的博客
08-28 913
String被声明为final的,不可被继承String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小String在jdk8及以前内部定义了用于存储字符串数据。JDK9时改为byte[]
24- 字符串拼接底层原理
记录java学习日常~
09-07 183
当在Java中进行字符串拼接时,底层的原理会根据使用的方式不同而有所不同。
String字符串拼接 底层原理
灿的博客
08-15 436
String字符串拼接的原理, 如String s = "abd" + "cff"
String的拼接字符串的底层实现原理
fll980205的博客
09-13 1987
下面代码: public class Test1 { public static void main(String[] args) { String str1="hello"; String str3="hello word!"; String str4=str1+"word!"; System.out.println(str...
优化字符串拼接
qq_21119289的博客
02-17 518
var str="我喜欢我可爱的女朋友,"; str=str+"她叫喵喵,"; str=str+"她时而可爱,时而认真,"; str=str+"她那天真的笑声可以让人忘掉一切烦恼。"; console.log(str);这里的优化主要是对加号操作符的优化,因为加号在JavaScript中非常耗时和耗内存,需要经过以下六步:1、首先开辟一块临时空间,存储字符串, 2、然后在开辟一块空间 3、把st
String字符串拼接原理剖析
weixin_30692143的博客
08-13 166
String a ="ab"+"c"; 这时候生成的"abc"会放入StringPool(正解), String a="ab"; String c=b+"c"; 由于和字面量"c"进行+运算的是一个对象而不是字面量,这样Java虚拟机就会在堆里面生成一个新的对象并返回该对象引用,此时变量a和变量c指向了两个不同的地址。 即使String a = new String("abc...
Java教程之String底层原理和版本演变
CZ-001的博客
09-05 981
intern() 方法将这个字符串对象尝试放入常量池中,并返回地址。jdk1 . 6 中:如果池中有,则不会放入,返回已有的池中的对象的地址。如果池中没有,则把此对象重新创建一份,放入池中,并返回池中新的对象地址。jdk1 . 7 起:如果池中有,则不会放入,返回已有的池中的对象的地址。如果池中没有,则把此对象的引用地址复制一份,放入池中,并返回池中的引用地址。
String的特性及字符串常量池(intern()的使用、字符串的拼接详解)
See_Csdn_的博客
10-29 520
文章目录12. String的特性12.1 String的基本特性12.1.1 StringTable12.2 String的内存分配12.3 字符串的拼接12.4 intern()的使用12.5 new String() 12. String的特性 12.1 String的基本特性 String声明为final的,不可被继承 String s1 = "ILOVEYOU";//字面量的定义方式 String s2 = new String("ILOVEYOU"); String实现了serial
字符串拼接的性能考量:String库的优化策略,加速你的代码运行
[字符串拼接的性能考量:String库的优化策略,加速你的代码运行](https://www.simplilearn.com/ice9/free_resources_article_thumb/StringBuilderEx2.png) # 1. 字符串拼接的性能基础 在软件开发中,字符串拼接是一...
String拼接字符串底层原理
qq_35425070的博客
11-19 8664
JDK版本:1.8 先上结果: 原理:jdk1.8之后字符串拼接底层就是创建了一个StringBuilder,然后调用append方法,最后调用toString转化成String 结论:java9之前,StringBuilder的append方法效率永远大于用+拼接,且拼接次数越多,差距越大! (9之后呢?https://blog.csdn.net/qq_35425070/article/...
字符串拼接操作底层原理
实践求真知
07-18 521
一 点睛 拼接操作的底层其实使用了 StringBuilder 二实战——左右两边如果是变量的字符串拼接 1代码 @Test public void test3() { String s1 = "a"; String s2 = "b"; String s3 = "ab"; // 存储在堆中字符串常量池中 /* s1 + s2 的执行细节:(变量s是临时定义的) ① StringBuilder s = new StringBuilder(); ...
性能优化--string 字符串拼接(超详细)
游戏码农一枚,不定时分享技术文章~
09-12 3050
性能优化--string 字符串拼接(超详细)
String字符串拼接原理
m0_51358164的博客
09-28 3319
String字符串拼接原理
编程之路小细节-字符串拼接以及优化的浅析
Mike_Linux的博客
12-06 386
程序功能的优化StringBuilder和String字符串拼接,程序优化的方式
String字符串拼接符 “+”底层原理
YXK
09-14 7954
字符串常量的拼接 String str3="hello"+" word!"; String str4="hello word!"; System.out.println(str3==str4); //运行结果:true原因:JVM编译器对字符串做了优化,在编译时str3就已经被优化成“hello Word!”,str3和str4指向字符串常量池同一个字符串常量,所以==比较为tr
关于字符串拼接优化
luca的博客
04-10 746
优秀的前端工程师,应该熟悉后端之道。    ---菜鸟自述 在探讨Java的路上欲走越远,发现企业级开发使用json拼串,喜欢使用StringBuffer中apend方法进行连接,原理因为StringBuffer在内存空间使用上,不会开辟新的变量,而会在自己原有的基础上进行操作。这样大大减少了内存消耗,但作为前端工程师一般使用“+”进行连接字符串,做了以下测试: function S
字符串拼接优化
qq_34884421的博客
11-12 140
using System.Collections; using System.Collections.Generic; using System.Text; using UnityEngine; public class CSStringBuilder { public static CSStringBuilder CS { get; set; } = new CSStringBuilder(); public StringBuilder sb = new StringBuilder(10
字符串变量拼接底层原理
Alphr的博客
05-23 683
与字面量的字符串拼接不同,有变量的字符串拼接要复杂得多,非常有必要进行研究 public static void main(String[] args){ String s1 = "a"; String s2 = "b"; String s3 = "ab"; String s4 = s1 + s2; System.out.println(s4 == s3); } 程序运行结果是false,至于底层是怎样进行操作的,我们
写文章

热门文章

  • String类相关知识(包含intern方法)及字符串拼接的底层原理和优化 801
  • Java基础之初识面向对象(包、继承、多态、抽象类、接口) 296

分类专栏

  • JAVASE 2篇
  • 数据结构

最新评论

  • String类相关知识(包含intern方法)及字符串拼接的底层原理和优化

    早上真起不来!: 支持支持

  • String类相关知识(包含intern方法)及字符串拼接的底层原理和优化

    秃头宝贝.: 😂😂

  • String类相关知识(包含intern方法)及字符串拼接的底层原理和优化

    秃头宝贝.: 😂

  • String类相关知识(包含intern方法)及字符串拼接的底层原理和优化

    NUC_Dodamce: 触及我知识盲区了哈哈

  • String类相关知识(包含intern方法)及字符串拼接的底层原理和优化

    秃头宝贝.: 感谢支持!

大家在看

  • springmvc源码流程解析(一)
  • 中英双语酒店管理系统——pms系统,海外版
  • 论文 Python 实现WOA-CNN-BiGRU-Attention数据分类预测 64

最新文章

  • Java基础之初识面向对象(包、继承、多态、抽象类、接口)
2021年2篇

目录

目录

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家大庆卡通玻璃钢雕塑定制哪里有商场美陈春节玻璃钢寺庙佛像雕塑加工定制沈阳水果玻璃钢雕塑定做白山玻璃钢雕塑设计性价比高玻璃钢十二生肖雕塑杭州仿铜西式玻璃钢雕塑小店玻璃钢花盆花器商场内美陈仿真草皮怎么固定景德玻璃钢人物雕塑石首玻璃钢座椅雕塑红塔区玻璃钢雕塑代理水型玻璃钢花盆透气吗广东玻璃钢牛动物雕塑景观装饰洛阳广场标识校园玻璃钢雕塑定做玻璃钢鹿雕塑玻璃钢仿紫铜人物雕塑玻璃钢仿铜人物雕塑图片深圳景观玻璃钢雕塑供应商临汾玻璃钢卡通座椅雕塑泰州蛋型玻璃钢花盆六盘水玻璃钢雕塑设计公司北京大型主题商场美陈市场馆陶玻璃钢花盆花器玻璃钢仿生雕塑哪家靠谱承德玻璃钢雕塑定做玻璃钢花盆技术上海玻璃钢陶瓷雕塑尺寸平顶山哪里有玻璃钢彩绘雕塑厂家罗源玻璃钢雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化