วิธีที่ดีที่สุดในการสร้าง enum ของสตริง?


364

วิธีที่ดีที่สุดในการมีenumประเภทเป็นชุดของสตริงคืออะไร?

ฉันลองสิ่งนี้:

enum Strings{
   STRING_ONE("ONE"), STRING_TWO("TWO")
}

ฉันจะใช้มันเป็นStringsอย่างไร

คำตอบ:


605

ฉันไม่รู้ว่าคุณต้องการทำอะไร แต่นี่คือวิธีที่ฉันแปลรหัสตัวอย่างของคุณ ....

package test;

/**
 * @author The Elite Gentleman
 *
 */
public enum Strings {
    STRING_ONE("ONE"),
    STRING_TWO("TWO")
    ;

    private final String text;

    /**
     * @param text
     */
    Strings(final String text) {
        this.text = text;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return text;
    }
}

textหรือคุณสามารถสร้างวิธีทะเยอทะยานสำหรับ

ตอนนี้คุณสามารถทำได้ Strings.STRING_ONE.toString();


3
ฉันไม่รู้ว่านี่เป็นข้อกำหนดของคอมไพเลอร์หรือไม่ แต่private String textควรเป็นที่สิ้นสุด
Jonathan

7
@ Tomás Narros ใช่คุณยังคงสามารถกำหนดมันใน Constructor ได้ตราบใดที่คุณไม่ได้ให้คุณค่าเมื่อคุณประกาศมันเป็นครั้งสุดท้าย
โจนาธาน

28
@The Elite Gentleman มันจะไม่ดีถ้าค่าของค่าคงที่ enum เปลี่ยนไประหว่างรันไทม์ดังนั้นแม้ว่าจะไม่จำเป็นก็ตามfinalก็จะดีที่สุด
Jonathan

8
อย่าลืม Enums ที่ไม่สามารถสร้างด้วยเป็นตัวสร้างเป็นnew privateโดยพื้นฐานแล้วการสร้างวัตถุเป็นสิ่งต้องห้ามและfinalไม่จำเป็นในกรณีนี้
Buhake Sindi

6
@BuhakeSindi: มันเป็นเรื่องจริง แต่บังเอิญมีคนหนึ่งอาจโน้มน้าวให้setText(String)enum และนั่นสามารถปลดปล่อยนรก :) finalประเภทของเอกสารที่คุณตั้งใจว่ามันคงที่ด้วยการสนับสนุนคอมไพเลอร์ ถ้าคุณจะใช้Stringค่าคงที่คุณจะไม่ประกาศว่าเป็นpublic static Stringใช่มั้ย
TWiStErRob

104

ค่าสตริงแบบกำหนดเองสำหรับ Enum

จากhttp://javahowto.blogspot.com/2006/10/custom-string-values-for-enum.html

ค่าสตริงเริ่มต้นสำหรับ java enum คือค่าใบหน้าหรือชื่อองค์ประกอบ อย่างไรก็ตามคุณสามารถปรับแต่งค่าสตริงได้โดยการแทนที่เมธอด toString () ตัวอย่างเช่น,

public enum MyType {
  ONE {
      public String toString() {
          return "this is one";
      }
  },

  TWO {
      public String toString() {
          return "this is two";
      }
  }
}

การรันโค้ดทดสอบต่อไปนี้จะทำให้เกิดสิ่งนี้:

public class EnumTest {
  public static void main(String[] args) {
      System.out.println(MyType.ONE);
      System.out.println(MyType.TWO);
  }
}


this is one
this is two

16
นี่ไม่ใช่วิธีที่มีประสิทธิภาพในการทำเช่นนี้ สิ่งนี้จะสร้างคลาสที่กำหนดเองใหม่สำหรับทุกค่าในการแจงนับ ในตัวอย่างข้างต้นคุณจะเห็นสิ่งต่อไปนี้ในbinไดเรกทอรี: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class ซึ่งจะเพิ่มขึ้นอย่างรวดเร็วจริง ดีที่สุดที่จะทำมันเป็นคำตอบที่คาดหวังโดยการส่งผ่านค่าไปยังตัวสร้าง enum ที่จริงผมไม่เห็นด้วยกับการเอาชนะtoString(); ฉันเชื่อว่าการใช้ getter ที่ชัดเจนนั้นดีกว่าเช่นgetKey()เนื่องจากการลบล้างtoString()อาจไม่คาดคิดโดยผู้ใช้ enum รายอื่น
Matt Quigley

เห็นด้วยกับ @MattQuigley การทำเช่นนั้นสนับสนุนให้ผู้ใช้ใช้ toString สำหรับสิ่งที่ไม่ควรใช้ หากคุณต้องการป้ายกำกับคุณควรเพิ่มแอตทริบิวต์ป้ายกำกับ
Sebastien Lorber

นอกจากนี้ยังไม่มีวิธีที่จะไปทางอื่น ๆ (จากสตริงไปยังวัตถุ enum) ซึ่งอาจจะต้องมีในบางจุด
Adrian Smith

การแทนที่ toString จะไม่ส่งผลกระทบต่อ valueOf () ใช่ไหม?
Dmitriusan

69

ใช้name()วิธีการ:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.ONE.name());
    }
}

enum Strings {
    ONE, TWO, THREE
}

ONEอัตราผลตอบแทน


17
ใช่ แต่Strings.STRING_ONE.name()ให้ผลตอบแทน "STRING_ONE" ไม่ใช่ "ONE" นี่ไม่ใช่คำตอบที่ดี คุณไม่มีสตริงใด ๆ ที่จะไม่ใช่ตัวระบุ Java ที่ถูกต้องและอื่น ๆ
Mark Peters

2
@ Mark จริงมันไม่สามารถจัดการกับตัวละครใด ๆ หาก OP ต้องการเพียงตัวอักษรตัวเดียวทางออกนี้จะตรงไปกว่าคำแนะนำของ The Elite Gentleman แต่แน่นอน: หากช่วงของอักขระเกินกว่าที่ตัวระบุ Java ที่ถูกต้องสามารถมีได้นี่คือไม่มีการเดินทาง จุดดี.
Bart Kiers

มันสมเหตุสมผลมากที่จะมีการตั้งชื่อแบบแผนภายในสำหรับ enum ที่แตกต่างจากสิ่งที่เราต้องการแสดงด้วย toString () (โดยเฉพาะถ้าผู้ใช้เห็นผลลัพธ์) ดังนั้นฉันไม่คิดว่านี่เป็นสิ่งที่ OP ทำ กำลังมองหา.
Michael McGowan

17
ผลลัพธ์จากname()อาจได้รับผลกระทบจากโปรแกรม obfuscator ฉันพบปัญหาที่คล้ายกันเมื่อไม่นานมานี้ ตัวอย่างเช่นด้วย Proguard คุณต้องหลีกเลี่ยงปัญหานี้ ดูการประมวลผลคลาสการแจกแจง
noisecapella

มันยอดเยี่ยมมาก ทำงานร่วมกับค่าเช่น: var_name, var_superlong_but_not_toooooo_long_name, ฯลฯ แม้กระทั่ง (โดยไม่ต้องจุด

18

ตั้งค่าชื่อ enum ให้เหมือนกับสตริงที่คุณต้องการหรือโดยทั่วไปคุณสามารถเชื่อมโยงแอททริบิวต์ที่ไม่มีกฎเกณฑ์กับค่า enum ของคุณ:

enum Strings {
   STRING_ONE("ONE"), STRING_TWO("TWO");
   private final String stringValue;
   Strings(final String s) { stringValue = s; }
   public String toString() { return stringValue; }
   // further methods, attributes, etc.
}

สิ่งสำคัญคือการมีค่าคงที่ที่ด้านบนและวิธีการ / คุณลักษณะที่ด้านล่าง


และยังมีคอนสตรัคเตอร์ส่วนตัวอีกด้วย
Buhake Sindi

1
ก่อสร้าง enum เป็นส่วนตัวโดยค่าเริ่มต้นและไม่จำเป็นต้องปรับปรุงการเข้าถึง แต่นั่นเป็นจุดที่ดีเกี่ยวกับตัวดัดแปลงการเข้าถึงโดยทั่วไปฉันได้อัปเดตรหัสของฉันเพื่อเพิ่มลงในแอตทริบิวต์และตัวเข้าถึง
Adrian Smith

15

ขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "ใช้พวกเขาเป็นสตริง" คุณอาจไม่ต้องการใช้ enum ที่นี่ ในกรณีส่วนใหญ่การแก้ปัญหาที่เสนอโดย The Elite Gentleman จะช่วยให้คุณสามารถใช้พวกเขาผ่านทาง toString-methods เช่นในSystem.out.println(STRING_ONE)หรือString s = "Hello "+STRING_TWOเมื่อคุณต้องการ Strings (เช่นSTRING_ONE.toLowerCase()) คุณอาจต้องการกำหนดให้เป็นค่าคงที่:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}

5
จริงๆแล้วนี่คือสิ่งที่ฉันพยายามหลีกเลี่ยง ... !
Dori

ที่จริงแล้วถ้าพวกเขาต้องการtoLowerCase()วิธีแก้ปัญหาของฉันพวกเขาก็สามารถไปStrings.STRING_TWO.toString().toLowerCase()ได้
Buhake Sindi

แน่นอน แต่นั่นไม่ได้ใช้พวกเขาเป็นสตริงตามที่ฉันตีความมัน เนื่องจาก Rrackham ไม่ต้องการการใช้งานแบบนี้เขาจึงควรใช้โซลูชัน enum ที่เสนอ
hd42

6
คุณไม่ควรใช้interfaceแทนfinalคลาสกับตัวprivateสร้าง มันเป็นการฝึกที่ท้อแท้
Aleks N.

1
@mils โซลูชันที่ใช้ enums ทำงานได้ดีในสวิตช์ ฉันจะแนะนำวิธีแก้ปัญหานี้เฉพาะในกรณีที่จำเป็นต้องใช้ Strings โดยตรง
hd42

8

คุณสามารถใช้สำหรับ Enum สตริง

public enum EnumTest {
    NAME_ONE("Name 1"),
    NAME_TWO("Name 2");

    private final String name;

    /**
     * @param name
     */
    private EnumTest(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

และโทรจากวิธีหลัก

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}

5

หากคุณไม่ต้องการใช้ตัวสร้างและคุณต้องการมีชื่อพิเศษสำหรับวิธีลองสิ่งนี้:

public enum MyType {
  ONE {
      public String getDescription() {
          return "this is one";
      }
  },    
  TWO {
      public String getDescription() {
          return "this is two";
      }
  };

  public abstract String getDescription();
}

ฉันสงสัยว่านี่เป็นวิธีแก้ปัญหาที่เร็วที่สุด ไม่มีความจำเป็นที่จะใช้เป็นตัวแปรสุดท้าย


แต่ด้วยสิ่งนี้คุณยังต้องโทรหา getDescription () ซึ่งผู้ถามต้องการโทรหา ONE หรือเข้าถึงเป็นค่าคงที่
kinsley kajiva

ฉันชอบสิ่งนี้ จะเกิดอะไรขึ้นหากจำเป็นต้องรับข้อมูลเพิ่มเติม ด้วยโซลูชันนี้เพียงเพิ่มวิธีนามธรรมที่ได้รับการป้องกันและแทนที่ ไม่จำเป็นต้องแทนที่เมธอด toString () มันสะอาดและสามารถยอมรับได้ว่าเป็นคำตอบที่ดีที่สุด
Arundev

0

รับและตั้งค่าเริ่มต้น

public enum Status {

    STATUS_A("Status A"),  STATUS_B("Status B"),

    private String status;

    Status(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.