1. String####

下面代码创建了几个对象?

  1. String s1 = new String("Hello");
  2. String s2 = new String("Hello");

要想答对这道题,需要考虑String的一个常量池的概念。在执行代码的时候,首先会判断字符串常量池中是否存在"Hello",如果存在,直接返回该对象的引用,那对于本题就是创建2个对象。如果不存在,则现在常量池中创建,加起来就三个对象了(一个对象两个引用)。

  1. 1. 什么样的字符串才会放在常量池中呢?
  2. 首先,只有字符串对象才会放在常量池中。(String a = "abc""abc"是字符串对象)
  3. 其次,只有在编译期确定的字符串才会被放在常量池中。
  4. 2. 考虑一下,常量池实在堆区还是方法区?
  5. jdk1.6以及之前,是在方法区的,1.7及以后,是在堆区的。

下面代码的结果呢?创建了几个对象呢?

  1. String s1 = "Java";
  2. String s2 = "从0到1";
  3. String s3 = s1 + s2;
  4. String s4 = "Java从0到1";
  5. System.out.println(s3 == s4);

不考虑常量池中存在字符串,首先一眼看出至少三个,"Java","从0到1","Java从0到1"。比较麻烦的就是String s3 = s1 + s2;我们知道的是"Java","从0到1","Java从0到1"是在编译期确定,放在字符串常量池中的。s3的值在编译期间确定不了,是放在堆中,最后的值是"Java从0到1",这是第四个了,那这个值是如何得到的呢?s1和s2相加得到,但是s1和s2是在常量池中的,s3是在常量池之外的堆中的,所以必须拷贝s1和s2到常量池外的堆中,这又是两个,现在看来,一共是创建了6个对象

那程序的结果就很明显了,结果是false。

加深理解,可以运行下面的代码:

  1. String s1 = new String("Hello");
  2. String s2 = s1;
  3. s2 = "Java";
  4. System.out.println(s1);
  5. System.out.println(s2);
  6. System.out.println("==========================");
  7. String s3 = "Java";
  8. String s4 = new String("Java");
  9. System.out.println(s2 == s3);
  10. System.out.println(s3 == s4);
  11. System.out.println(s1.hashCode());
  12. System.out.println(s2.hashCode());
  13. System.out.println(s3.hashCode());
  14. System.out.println(s4.hashCode());
  15. System.out.println("===========================");
  16. System.out.println(System.identityHashCode(s1));
  17. System.out.println(System.identityHashCode(s2));
  18. System.out.println(System.identityHashCode(s3));
  19. System.out.println(System.identityHashCode(s4));

要注意的是String s = "Hello" 和 String s = new String("Hello"); 的区别,在我看来,前一个s是个引用,放在常量池中(有点疑惑还得认真研究),而s是存放在堆上非常量池中,"Hello"是放在常量池中。

2. String被设计为不可变的好处。####

  1. 1. 被设计为不可变,字符串池才可以实现。
  2. 2. 字符串不可变,不会造成线程安全问题,同一个字符串实例可以被多个线程共享,不用考虑同步,因为String本来就是线程安全。
  3. 3. 字符串的不可变,保证了哈希码的唯一性,在创建的时候hashcode就被缓存,不用重新计算。使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。

3. final修饰类####

首先要明确,final修饰的类是不可被继承的。比如说String类就是被final修饰符修饰,就不可被继承。相当于上锁,

什么时候使用?当你确定某一个类是完美的,不需要进行任何的修改和扩展,这个时候可以讲类声明为final。

4. final修饰成员变量####

final修饰的成员变量只可被初始化一次,不可更改。

5. final修饰方法####

final修饰方法,该方法不可被子类重写覆盖,但可以在本类中进行重载,并且可以被正常调用。

6. final修饰成员变量和普通变量的区别####

  1. String a = "hello1";
  2. final String b = "hello";
  3. String c = "hello";
  4. String d = b + 1;
  5. String e = c + 1;
  6. System.out.println(a == d);
  7. System.out.println(a == e);

结果是什么呢?true和false!!!为什么呢?这个原因是因为final修饰变量在编译期间可以被直接替换,也就意味着在d=b+1的时候,d="hello"+1,即为"hello1",编译期确定的值在常量池中,d和a的引用是相同的,所以a==b是true,而e是在运行期确定的,在堆的非常量池中,引用不同,所以a==e是false。

7. final和static####

首先注意:

  1. static用来表示唯一,独此一份,也即是静态,但是是可变的。
  2. final用来表示不可变。

理解:static表示无论创建多少个对象,每个对象中被static修饰的成员变量都是相同的值。但是fianl表示每个对象中被fianl修饰的成员变量是不可更改的,一旦确定就不可能再修改。

8. static方法####

static方法叫做静态方法,静态方法属于类,不属于对象,也就是可以直接使用类名来调用。在静态方法中不能调用非静态方法和非静态成员变量,但是非静态方法可以访问静态方法和成员变量(这两句话怎么理解呢?可以从加载类的顺序考虑,类的加载会先加载静态的成员变量和方法,之后是构造方法,非静态的成员变量和方法)。

还有一个问题,就是构造方法是静态的吗?经过尝试,构造方法不能使用static修饰,但是在静态代码块中可以直接调用,因此可以得出,构造方法不是静态的,但他具有静态方法的一些特性,比如说可以在静态方法中被调用。

9. static成员变量####

静态变量被所有对象共享,即属于类,也就是在初次加载的时候被初始化,之后每次创建对象都不会初始化。而非静态变量是属于对象的,在每次创建对象都会有不同的赋值。

10. static代码块####

静态代码块可以用来优化程序性能,对于某些变量,只需要初始化一次等,这个时候就可以放在静态代码块,静态代码块永远只会执行一次。

11. static注意点####

  • static是不允许用来修饰局部变量。
  • static变量和方法可以使用对象来调用(this等)。
  • java类关于静态的加载时间,单个类的话,没有创建对象,只会执行静态成员变量和静态代码块。创建对象会在前面的基础上依次执行初始化成员变量,代码块,构造方法。也就是这样: 静态成员变量 --> 静态代码块 --> 成员变量 --> 代码块 --> 构造函数。 如果存在子父类继承呢?父类静态成员变量 --> 父类静态代码块 -->子类静态成员变量 --> 子类静态代码块 --> 父类成员变量 --> 父类代码块 --> 父类构造函数 --> 子类成员变量 --> 子类代码块 --> 子类构造函数

按照上面的顺序看看下面的代码的执行结果:

  1. public class Test {
  2. Person person = new Person("Test");
  3. static{
  4. System.out.println("test static");
  5. }
  6. public Test() {
  7. System.out.println("test constructor");
  8. }
  9. public static void main(String[] args) {
  10. new MyClass();
  11. }
  12. }
  13. class Person{
  14. static{
  15. System.out.println("person static");
  16. }
  17. public Person(String str) {
  18. System.out.println("person "+str);
  19. }
  20. }
  21. class MyClass extends Test {
  22. Person person = new Person("MyClass");
  23. static{
  24. System.out.println("myclass static");
  25. }
  26. public MyClass() {
  27. System.out.println("myclass constructor");
  28. }
  29. }
  30. // 结果为
  31. test static
  32. myclass static
  33. person static
  34. person Test
  35. test constructor
  36. person MyClass
  37. myclass constructor

String,static,final的更多相关文章

  1. String的实例化与static final修饰符

    String两种实例化方式 一种是通过双引号直接赋值的方式,另外一种是使用标准的new调用构造方法完成实例化.如下: String str = "abcd"; String str ...

  2. Java 关键字static final使用总结

    Static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被 ...

  3. 为什么接口要规定成员变量必须是public static final的呢?(转)

    在interface里面的变量默认都是public static final 的.所以可以直接省略修饰符: String param="ssm"://变量需要初始化 为什么接口要规 ...

  4. The serializable class does not declare a static final serialVersionUID field of type long

    在编译以下Java程序时,出现The serializable class  does not declare a static final serialVersionUID field of typ ...

  5. Static Final用法

    一.final数据 在 java编程语言中,有时候需要告知编译器一段数据是不变的编译期常量.对于这种情况,编译器可以将此常量值带入需要用到它的计算式子当中,这种在编译时 执行计算式的方法减轻了运行时的 ...

  6. JDK源码学习--String篇(二) 关于String采用final修饰的思考

    JDK源码学习String篇中,有一处错误,String类用final[不能被改变的]修饰,而我却写成静态的,感谢CTO-淼淼的指正. 风一样的码农提出的String为何采用final的设计,阅读JD ...

  7. 静态常量(static final)在class文件里是如何的呢?

    近期写项目遇到一个问题,来回折腾了几次,最终探究清楚了.不废话.上样例. 背景:由于项目小,没有使用配置文件,全部静态常量都放在Config.java里面了 public class Config { ...

  8. private static final long serialVersionUID = 1L;详解

    public class User implements Serializable { /** * serialVersionUID */ private static final long seri ...

  9. Java反射-修改字段值, 反射修改static final修饰的字段

    反射修改字段 咱们从最简单的例子到难, 一步一步深入. 使用反射修改一个private修饰符的变量name 咱们回到主题, 先用反射来实现一个最基础的功能吧. 其中待获取的name如下: public ...

随机推荐

  1. could not launch process: decoding dwarf section info at offset 0x0: too short

    Fabric调试异常 作者在使用chaincode进行智能合约开发的过程中,使用Goland + Golang + win10_X64作为开发环境: GoLand 2018.1.4 Build #GO ...

  2. eclipse以MapReduce本地模式运行程序

    1.准备好所需的文件winutils.exe.hadoop-eclipse-plugin-2.7.3.jar.hadoop-common-2.2.0-bin-master.zip 下载路径:http: ...

  3. 基于C#的机器学习--目录

    转载请注明出处:https://www.cnblogs.com/wangzhenyao1994/p/10223666.html 文章发表的另一个地址:https://blog.csdn.net/wyz ...

  4. 机器学习算法 --- SVM (Support Vector Machine)

    一.SVM的简介 SVM(Support Vector Machine,中文名:支持向量机),是一种非常常用的机器学习分类算法,也是在传统机器学习(在以神经网络为主的深度学习出现以前)中一种非常牛X的 ...

  5. JavaScript中数组中遍历的方法

    前言 最近看了好几篇总结数组中遍历方法的文章,然而"纸上得来终觉浅",决定此事自己干.于是小小总结,算是自己练手了. 各种数组遍历方法 数组中常用的遍历方法有四种,分别是: for ...

  6. 2017年软件工程作业-“Hello World!”团队互评beta版本

    A.欢迎来怼——博客园安卓APP(测评人:刘淑霞) 博客地址:http://www.cnblogs.com/liusx0303/p/7905928.html B.Thunder——爱阅app(测评人: ...

  7. Thunder——Final发布

    视频: https://www.bilibili.com/video/av17008792/   视频播放截图及简要文字介绍: http://www.cnblogs.com/lick468/p/799 ...

  8. 2-Tenth Scrum Meeting20151210

    任务分配 闫昊: 今日完成:请假.(编译) 明日任务:参加会议讨论,安排任务分工. 唐彬: 今日完成:请假.(编译) 明日任务:参加会议讨论,安排任务分工. 史烨轩: 今日完成:请假.(编译) 明日任 ...

  9. WebGL学习笔记一

    学习用来做web3D的,从第一页开始学起先做2D的,接下来的程序是一个入门级的程序,可以通过在画板上的不同位置点击而获取不同颜色的点,以画板中心为坐标原点四个象限有不同的颜色,访问地址  http:/ ...

  10. <s:action>的一些用法

    Action标签,顾名思义,是用来调用Action的标签,在JSP中页面中,可以具体指定某一命名空间中的某一Action.而标签的主体用于显示及渲染Actionr的处理结果. action标签有如下几 ...