精华内容
下载资源
问答
  • Java定义常量字符串
    千次阅读
    2021-03-08 02:11:34

    我有一个常量字符串列表,需要在Java程序中的不同时间显示它们。

    在C语言中,我可以在代码顶部定义以下字符串:

    #define WELCOME_MESSAGE"Hello, welcome to the server"

    #define WAIT_MESSAGE"Please wait 5 seconds"

    #define EXIT_MESSAGE"Bye!"

    我想知道用Java做这种事情的标准方法是什么?

    static final String WELCOME_MESSAGE ="Hello";?

    你有做过研究吗?

    是的,但是我读了一些网站,他们说final不是java中的常量,所以我不

    Java中的@csss final表示无法更改引用-但指向的对象仍然可以更改。 对我们来说幸运的是,Java中的String是一个不可变的类,因此final String在这两个方面都是常量。

    通常,您可以在班级顶部定义此代码:

    public static final String WELCOME_MESSAGE ="Hello, welcome to the server";

    当然,根据使用此常量的位置,使用适当的成员可见性(public / private / protected)。

    香港专业教育学院一直想知道,如果将常量定义为私有,是否不必将常量设置为静态?

    不,它应该仍然是static。 每次实例化类型时,将其设置为私有和非静态仍将创建该字符串的新副本。 见stackoverflow.com/q/1415955/247763

    它看起来像这样:

    public static final String WELCOME_MESSAGE ="Hello, welcome to the server";

    如果常量仅在单个类中使用,则需要将其设为private而不是public。

    public static final String YOUR_STRING_CONSTANT ="";

    或行业中另一个典型的标准是拥有一个Constants.java命名类文件,其中包含要在项目中使用的所有常量。

    您可以使用

    public static final String HELLO ="hello";

    如果您有许多字符串常量,则可以使用外部属性文件/简单

    "固定持有人"类

    我们通常将常量声明为static。这样做的原因是因为Java在每次实例化该类的对象时都会创建非静态变量的副本。

    因此,如果我们使常量static不会这样做,则会节省内存。

    使用final,我们可以使变量恒定。

    因此,定义常量的最佳实践如下:

    private static final String YOUR_CONSTANT ="Some Value";

    访问修饰符可以为private/public,具体取决于业务逻辑。

    你错了。 由于JVM使用了字符串池,因此无助于节省内存。

    @Mirimas Nope。 老兄,你错了。 静态仅初始化一次,但每次初始化非静态变量的对象时,都会初始化一个非静态变量。

    这里使用了字符串池,因为您不使用" new"关键字来创建字符串。 因此,即使您不对字符串使用static,它也会使用已从字符串池创建的引用。 查看更多:stackoverflow.com/questions/3297867/

    只需使用

    final String WELCOME_MESSAGE ="Hello, welcome to the server";

    该指令的主要部分是"最终"关键字。

    更多相关内容
  • Java中的字符串常量

    千次阅读 2021-03-07 00:44:58
    ava中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");,这两种方式我们在代码编写时都经常使用,尤其是...

    ava中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("droid");,这两种方式我们在代码编写时都经常使用,尤其是字面量的方式。然而这两种实现其实存在着一些性能和内存占用的差别。这一切都是源于JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池。

    工作原理

    当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

    举例说明

    字面量创建形式

    String str1 = "droid";

    JVM检测这个字面量,这里我们认为没有内容为droid的对象存在。JVM通过字符串常量池查找不到内容为droid的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量str1。

    如果接下来有这样一段代码

    String str2 = "droid";

    同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”droid”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量str2。注意这里不会重新创建新的字符串对象。

    验证是否为str1和str2是否指向同一对象,我们可以通过这段代码

    System.out.println(str1 == str2);

    结果为true。

    使用new创建

    String str3 = new String("droid");

    当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。因此我们使用下面代码测试一下,

    String str3 = new String("droid");

    System.out.println(str1 == str3);

    结果如我们所想,为false,表明这两个变量指向的为不同的对象。

    intern

    对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。

    调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。

    String str4 = str3.intern();

    System.out.println(str4 == str1);

    输出的结果为true。

    疑难问题

    前提条件?

    字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。

    引用 or 对象

    字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。

    更新验证,收到的很多评论也在讨论这个问题,我简单的进行了验证。 验证环境

    22:18:54-androidyue~/Videos$ cat /etc/os-release

    NAME=Fedora

    VERSION="17 (Beefy Miracle)"

    ID=fedora

    VERSION_ID=17

    PRETTY_NAME="Fedora 17 (Beefy Miracle)"

    ANSI_COLOR="0;34"

    CPE_NAME="cpe:/o:fedoraproject:fedora:17"

    22:19:04-androidyue~/Videos$ java -version

    java version "1.7.0_25"

    OpenJDK Runtime Environment (fedora-2.3.12.1.fc17-x86_64)

    OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

    验证思路:以下的Java程序读取一个大小为82M的视频文件,以字符串形式进行intern操作。

    22:01:17-androidyue~/Videos$ ll -lh | grep why_to_learn.mp4

    -rw-rw-r--. 1 androidyue androidyue 82M Oct 20 2013 why_to_learn.mp4

    验证代码

    import java.io.BufferedReader;

    import java.io.FileNotFoundException;

    import java.io.FileReader;

    import java.io.IOException;

    public class TestMain {

    private static String fileContent;

    public static void main(String[] args) {

    fileContent = readFileToString(args[0]);

    if (null != fileContent) {

    fileContent = fileContent.intern();

    System.out.println("Not Null");

    }

    }

    private static String readFileToString(String file) {

    BufferedReader reader = null;

    try {

    reader = new BufferedReader(new FileReader(file));

    StringBuffer buff = new StringBuffer();

    String line;

    while ((line = reader.readLine()) != null) {

    buff.append(line);

    }

    return buff.toString();

    } catch (FileNotFoundException e) {

    e.printStackTrace();

    } catch (IOException e) {

    e.printStackTrace();

    } finally {

    if (null != reader) {

    try {

    reader.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    return null;

    }

    }

    由于字符串常量池存在于堆内存中的永久代,适用于Java8之前。我们通过设置永久代一个很小的值来进行验证。如果字符串对象存在字符串常量池中,那么必然抛出java.lang.OutOfMemoryError permgen space错误。

    java -XX:PermSize=6m TestMain ~/Videos/why_to_learn.mp4

    运行证明程序没有抛出OOM,其实这个不能很好的证明存储的是对象还是引用。

    但是这个至少证明了字符串的实际内容对象char[]不存放在字符串常量池中。既然这样的话,其实字符串常量池存储字符串对象还是字符串对象的引用反而不是那么重要。但个人还是倾向于存储的为引用。

    优缺点

    字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间。

    如果硬要说弊端的话,就是牺牲了CPU计算时间来换空间。CPU计算时间主要用于在字符串常量池中查找是否有内容相同对象的引用。不过其内部实现为HashTable,所以计算成本较低。

    GC回收?

    因为字符串常量池中持有了共享的字符串对象的引用,这就是说是不是会导致这些对象无法回收?

    首先问题中共享的对象一般情况下都比较小。据我查证了解,在早期的版本中确实存在这样的问题,但是随着弱引用的引入,目前这个问题应该没有了。

    intern使用?

    关于使用intern的前提就是你清楚自己确实需要使用。比如,我们这里有一份上百万的记录,其中记录的某个值多次为美国加利福尼亚州,我们不想创建上百万条这样的字符串对象,我们可以使用intern只在内存中保留一份即可。关于intern更深入的了解请参考深入解析String#intern。

    总有例外?

    你知道下面的代码,会创建几个字符串对象,在字符串常量池中保存几个引用么?

    String test = "a" + "b" + "c";

    答案是只创建了一个对象,在常量池中也只保存一个引用。我们使用javap反编译看一下即可得知。

    17:02 $ javap -c TestInternedPoolGC

    Compiled from "TestInternedPoolGC.java"

    public class TestInternedPoolGC extends java.lang.Object{

    public TestInternedPoolGC();

    Code:

    0: aload_0

    1: invokespecial #1; //Method java/lang/Object."":()V

    4: return

    public static void main(java.lang.String[]) throws java.lang.Exception;

    Code:

    0: ldc #2; //String abc

    2: astore_1

    3: return

    看到了么,实际上在编译期间,已经将这三个字面量合成了一个。这样做实际上是一种优化,避免了创建多余的字符串对象,也没有发生字符串拼接问题。关于字符串拼接,可以查看Java细节:字符串的拼接。

    展开全文
  • 有些人使用整数或字符串定义常量,而另一些人则使用枚举。我还遇到了在它们自己的接口中定义常量——在接口中,使用常量的类必须实现接口。这种策略通常被称为接口常量设计模式。在本文中,我们将了解在Java中...

    关于Java中常量的话题似乎有很多困惑。有些人使用整数或字符串来定义常量,而另一些人则使用枚举。

    我还遇到了在它们自己的接口中定义的常量——在接口中,使用常量的类必须实现接口。这种策略通常被称为接口常量设计模式。

    在本文中,我们将了解在Java中存储常量的两种最常见的策略:整数和枚举。

    首先也是最重要的,当你决定使用常量时,你应该非常确定常量不会随着时间而改变,这样你就可以避免重新编译。

    在这篇文章中,我们将使用一个非常常见的常量候选——工作日!

    假设我们有一个表示在线商店中订单的类,我们希望在其中跟踪订单发生在一周中的哪一天。

    看起来是这样的:

    00ae88e2b3c8bae68f210da740ba999c.png

    请注意,该类暂时不会编译-[数据类型]只是我们将使用的常量类型的占位符。

    用整数定义常数

    在Java中,定义常量最常用的方法之一是通过整数,其中整数变量是静态的。

    37a005748b871900d2ae087b33c2ce04.png

    定义整数常量时要问的第一个问题是将它们放置在何处。我们是否将它们直接放在班级中?还是给他们上课?

    由于days非常通用,而且不一定只连接到Order类型的对象,因此我们将在它们自己的类WeekDay中定义它们。

    e0d87bd9bb94ccf439fdca5a29390ac2.png

    你可能注意到了私有构造函数——这是为了避免客户端实例化类。该类只保存静态变量,这些变量没有绑定到对象,因此不需要实例化该类。

    现在,每当我们需要为订单设定一个特定的日期时,我们都会这样做:

    08f0c815ee01b884b7012a247f2a326b.png

    当我们想检查订单是否发生在星期五时,我们可以简单地调用write:

    90c7acff285319ebe94619bc89055f32.png

    到目前为止,还不错。这个设计肯定不会有什么问题吧?

    假设你一年后会回到这个代码,你必须检查下订单是否在周一发生。

    在这种情况下,可以尝试以下方法:

    0bfd506ee62231865df993136d2aaf7d.png

    在那一刻,完全忘记了WeekDay类,这段代码非常有意义。星期一是一周的第一天,所以工作日应该是1,对吧?

    但不是,因为静态int变量Monday在我们的WeekDay类中定义为0!

    这是一个很好的例子,说明了为什么应该考虑避免使用整数常量。它们容易出错和混淆,并且很难调试。

    用枚举定义常量

    在Java中定义常量的另一种方法是使用枚举。

    当使用枚举时,常量类将如下所示:

    75c745318e4e6c4ab76db86ad278c97c.png

    注意,没有私有构造函数-不需要程序员(你!)强制该类是不可实例化的,因为枚举在默认情况下是不可实例化的!

    将工作日设置为顺序的语法与整型常量的语法完全相同:

    05e4003ef729b67820e13779a8a109be.png

    我们如何在星期五处理订单也没有什么不同:

    ff41aa7b44d220c2776f93d447098c4e.png

    关键的区别在于,这是在Order类中设置和比较weekday变量值的唯一方法。

    order.setWeekDay(1);和if(order.getWeekDay()==1)都会使编译器抛出一个错误,因为试图使用integerDay类型的变量,而它们应该是WeekDay类型。

    回想一下你完全忘记了的情景。

    对于枚举,这不再是一个问题。如果尝试使用整数而不是工作日枚举的成员,编译器只会抛出一个错误,告诉您需要使用工作日枚举。

    换言之,唯一能检查订单是否在星期五发生的是:

    5c94d1b18fced049c9b6d53615caaa4b.png

    就如上面这样,再清楚不过了。

    不再被迫记住constants类,如果有任何客户机要使用您的代码,他们不必怀疑Monday实际上是由0还是1表示的。

    我希望这个例子向您展示了为什么在定义常量时应该考虑在整数上使用枚举。

    枚举将使你的代码不易出错、更易于阅读和维护。

    展开全文
  • JAVA字符串常量和变量

    千次阅读 2020-09-16 17:35:41
    其中String为字符串常量,StringBuffer、StringBuilder均为字符串变量。即:String对象创建后是不可以更改的,举个例子说明一下: String str="abc"; str=str+"de"; System.out.println(str); 首先第一行创建一个...

    Java平台提供了两种字符串类型:String和StringBuffer、StringBuilder用来操作字符串。其中String为字符串常量,StringBuffer、StringBuilder均为字符串变量。即:String对象创建后是不可以更改的,举个例子说明一下:

    String str="abc";
    str=str+"de";
    System.out.println(str);
    

    首先第一行创建一个对象,并且把"abc"赋值给str,然后在第二行,虚拟机新建一个对象str并把之前str的值和"de"加起来再赋值给新str,原来的str被删除掉了,所以说String对象创建之后是不可以更改的;而StringBuffer和StringBuilder对象是变量,对变量操作就是对对象进行直接操作,不会进行创建,删除操作。所以说有些情况下String的执行速度是比较慢的,因为操作String对象时可能会有删除、新建操作。

    另外在线程安全方面,StringBuffer中很多方法都被synchronized关键字修饰,所以可以保证线程是安全的。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

    一些相关的面试题:
    1.

    String a = "hello2";
    
    String b = "hello" + 2;
    
    System.out.println((a == b));
    

    结果为true,“hello”+2在编译期间就已经被优化成"hello2",因此在运行期间,变量a和变量b指向的是同一个对象。
    2.

    String s1 = new String("abc");
    

    创建了几个对象?
    这行代码首先在栈中创建一个s1对象,然后再常量池中创建’abc’,然后在堆内存中复制一个’abc’的副本,但是有自己的地址,最后再把s1指向副本的地址。所以,这行代码创建了一个对象。如图:
    在这里插入图片描述
    3.
    判断定义为String类型的s1和s2是否相等

    String s1 = new String("abc");
    String s2 = "abc";
    System.out.println(s1 == s2); //false
    System.out.println(s1.equals(s2)); //true
    

    根据上题,s1指向的是堆内存中的地址,s2指向的是常量池。

    总结:String适合在少量字符串操作的情况下使用;StringBuilder适合单线程下在字符缓冲区进行大量操作的情况;StringBuffer适合多线程下在字符缓冲区进行大量操作的情况。

    展开全文
  • 浅谈JAVA字符串常量的储存位置

    千次阅读 2021-02-12 18:46:26
    在讲述这些之前我们需要一些预备知识:Java的内存结构我们可以通过两个方面去看待它。从该角度看的话Java内存结构包含以下部分:1、栈区:由编译器自动分配释放,具体方法执行结束后,系统自动释放JVM内存资源。其...
  • 字符串常量池, Class常量池, 运行时常量池
  • 字符串池也可以被称为字符串常量池,我认为这个名称就是产生误解的根源,有些人说着说着就把字符串三个字省略了,只剩下了常量池... 所以为了避免误解,我建议在指代字符串对象的缓存池的时候,就直接称之为字符串池...
  • java中的字符串和字符串常量

    千次阅读 2019-03-24 13:31:23
    String作为一种被Final修饰并按照不可变性设计的类,应当说某种程度上语言本身是希望开发者把它当做基本数据类型去使用的,然而...java本身又提供了一些构建和操作字符串的快捷或隐秘的方式,使用不当往往产生很多不...
  • 字符串变量相加vs字符串常量相加 public static void main(String[] args) { String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; System.out.println(s3==s1+s2);//结果为false System.out....
  • 【JavaSE系列】Java中的字符串之字符串常量

    千次阅读 多人点赞 2021-12-01 13:34:46
    本篇文章带大家认识Java基础知识——字符串类,在前面我们已经知道如何在Java定义字符串,本文将介绍Java字符串中的字符串常量池,探究字符串相等问题。
  • Java字符常量详解

    千次阅读 2021-02-12 09:47:42
    Java程序中经常会遇到类似于"Hello"这样地字符串,那么这种类型的字符串是Java中是如何存储,下面就来讨论一下字符串常量在内存中的存储方式Java程序在编译时会将程序中出现的常量(包括:char、byte、short、int、...
  • 【JavaSE】字符串常量池、String详解

    千次阅读 2022-02-11 15:48:38
    1.String Pool 1.1字符串常量池产生时间 1.2字符串常量池的位置 1.3字符串常量池的优点 2.String 2.1不可变性 2.2定义方式 2.2.1 字面量的方式 2.2.2 new的方式 2.2.3 intern()的方式
  • JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。JDK1.8开始,取消了Java方法区,取而代之的是位于直接内存的元空间(metaSpace)。已知:String A...
  • java 如何定义字符串变量

    千次阅读 2021-02-12 09:23:58
    展开全部java中可以使用String来定义一个字符串,见如下代32313133353236313431303231363533e78988e69d8331333431346335码,...字符串创建:stringName = new String(字符串常量);或stringName = 字符串常量;二、S...
  • 前言 String s1 = new String(“hello”); String s2 = “hello”; s1是字符串对象,s2和字符串常量,创建过程有何区别? 内存分配 ...栈中定义一个引用变量s2,编译程序先去字符串常量池检查,是否存在“h
  • Java中怎么定义字符串Java基础

    千次阅读 2021-11-26 15:20:20
    字符串是Java 中特殊的类,使用方法像一般的基本数据类型,被广泛应用在 Java 编程中。Java 没有内置的字符串类型,而是在标准 Java 类库中...因此也可以通过创建 String 类的实例来定义字符串。 不论使用哪种形式创...
  • java定义字符串数组

    2020-03-07 16:57:32
    各位大佬,java中怎么实现定义一个字符串数组,让每个索引对应一句话呀?(初学者(*^▽^*))3q~~
  • java string什么是字符串常量,什么是字符串数组,什么是字符串常量池?
  • 常量池就类似一个JAVA系统级别提供的缓存。  8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种: 1)直接使用双引号声明出来的String对象会直接存储在常量池中。
  • String:java:常量字符串过长

    千次阅读 2021-02-25 18:51:19
    问题:有一次定义一个超长的字符串,结果编译的时候就报错:Error:(59, 20) java: 常量字符串过长原因:(经过查阅资料才明白)String内部是bai以char数组的形式存储,数组的长度是int类型,那么String允许的最大长度...
  • Java定义字符串

    千次阅读 2019-07-03 20:01:14
    因此也可以通过创建 String 类的实例来定义字符串。 不论使用哪种形式创建字符串,字符串对象一旦被创建,其值是不能改变的,但可以使用其他变量重新赋值的方式进行更改。 直接定义字符串 直接定义字符串是指使用...
  • 不知道大家有没有遇到那种在java代码里用字符串写sql语句的情况,但是如果sql语句字符串的长度太长的话就会报错。代码如下: 代码A String str = "567890123456789...0123456789";//由于字符串长度太长,所以省略一...
  • 1、常量 常量java中就值的是一般的字面量,比如字符串,整数,浮点数等等数据。简单理解java中什么叫常量 2、常量池,也叫静态常量池,说常量池一定要指明是编译器生产
  • java的内存分配中,经常听到很多关于常量池的描述,我开始看的时候也是看的很模糊,网上五花八门的说法简直太多了,最后查阅各种资料,终于算是差不多理清了,很多网上说法都有问题,笔者尝试着来区分...
  • 作为最基础用的最多的引用数据类型,Java 设计者为String 提供了各种优化,其中就有为 String 提供了字符串常量池以提高其性能,主要就是为了降低内存开销,那么字符串常量池的具体原理是什么,我们带着以下三个问题...
  • 目录 1,常量池 1.1, class文件常量池 1.2, 运行时常量池 1.3,字符串常量池 String.intern() -XX:StringTableSize 2,使用new关键字和使用字符串字面...
  • 静态常量池指的是java代码中定义的常量,经过jvm编译... 字符串常量池指的是类加载完成后,经过验证、准备阶段之后放在字符串常量池中。字符串常量池的数据只会存储一份,被所有的类共享。基本流程是:创建字符串之...
  • 与其他语言不同,java不直接支持常量。但是,您仍然可以通过声明变量static和final来创建常量。静态-声明了静态变量后,它们将在编译时加载到内存中,即只有一个副本可用。Final-声明变量final后,就无法再次修改其...
  • Java String —— 字符串常量

    千次阅读 2019-02-01 11:37:53
    我们可以看一下jdk中的String.java源码(源码使用的是jdk1.8的版本),我简要的摘录如下: public final class String implements java.io.Serializable, Comparable<String&...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 186,699
精华内容 74,679
关键字:

java定义字符串常量

java 订阅