How is the method getAbbreviation() in an Enum class implemented?
The following code is from the book Core Java I.
public class EnumTest {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Enter a size: (SMALL, MEDIUM, LARGE, EXTRA_LARGE) ");
String input = in.next().toUpperCase();
Size size = Enum.valueOf(Size.class, input);
System.out.println("size=" + size);
System.out.println("abbreviation=" + size.getAbbreviation());
if (size == Size.EXTRA_LARGE) {
System.out.println("Good job--you paid attention to the _.");
}
}
}
enum Size {
SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL");
private Size(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
private String abbreviation;
}
The program execution picture is shown here.
My question is: why it can output abbreviation=S, how is it implemented internally?
It is an invocation of the enum constructor is an invocation of the enum constructor Size(String abbreviation).
Actually,the constructor of Enum class is private , programmer can not use it.So the provided code offered in the book
SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL");
is functionally the same to :
class Size{
private String abbreviation;
private Size(String abbreviation){this.abbreviation=abbreviation;}
public String getAbbreviation(){return abbreviation;}
public static Size SMALL = new Size("S");
public static Size MEDIUM = new Size("M");
public static Size LARGE = new Size("L");
public static Size EXTRA_LARGE = new Size("XL");
}
although i haven't found the source code of this implemention process,but I think it goes something like this.
Related
In the program I am making, I am trying to get a formatted season name for a given season(formatted so it . I keep the formatted names in an interface, since if I were to use a map, it would be unnecessarily regenerated, since I don't make an instance of TeamBuilder
The Seasons interface:
public interface Seasons {
/*
* Contains a formatted list of seasons.
*
* An interface is being used as an alternative to using a Map in the
* TeamBuilder class, since calling parseTeam would have to build
* mappings for the seasons each time it
* was called. This way, the formatted name can simply be grabbed
*/
final String Skyrise = "Skyrise";
final String Toss_Up = "Toss%20Up";
final String Sack_Attack = "Sack%20Attack";
final String GateWay = "Gateway";
final String Round_Up = "Round%20Up";
final String Clean_Sweep = "Clean%20Sweep";
final String Elevation = "Elevation";
final String Bridge_Battle = "Bridge%20Battle";
final String Nothing_But_Net = "Nothing%20But%20Net";
final String Starstruck = "Starstruck";
final String In_The_Zone = "In%20The%20Zone";
final String Turning_Point = "Turning%20Point";
}
The problem comes when I try to grab these seasons. My TeamBuilder class takes in an argument(String season), which is unformatted. My question is, is there any way that I can use a String argument for a method to get a specific item from an interface? This is the most preferable to using a HashMap, which would needlessly regenerate the same information
All these classes can be found on the Github page for this project.
If you want to do it in a typed way, you can use Enum for this:
enum Season{
Skyrise,Toss_Up, Sack_Attack;
#Override
public String toString() {
switch(this){
case Skyrise: return "Skyrise";
case Toss_Up: return "Toss%20Up";
case Sack_Attack: return "Sack_Attack";
default: return "";
}
}
}
public class main{
public static void printSeason(Seasons seasons){
System.out.println(seasons);
}
public static void main(String[] args) {
Seasons e = Seasons.Skyrise;
printSeason(e);
System.out.println(e);
}
}
Since the compiler internally invokes the toString(), you can pass the argument as a Seasons or a String like my example.
And if you still want to use a map without "unnecessarily regenerated" you can use a static field with static initializer like this:
class Seasons {
private static Map<String,String> map = new HashMap<>();
static {
map.put("Skyrise", "Skyrise");
map.put("Toss_Up", "Toss%20Up");
}
public static String getFormatted(String key){
return map.getOrDefault(key,"");
}
}
class main{
public static void main(String[] args) {
System.out.println(Seasons.getFormatted("Skyrise"));
}
}
Just to integrate on Snoob answer you can have enum with fields, so:
enum Season
{
Skyrise("Skyrise"),
Toss_Up("Toss%20Up"),
Sack_Attack("Sack%20Attack")
;
public final String fancyName;
private Season(String fancyName)
{
this.fancyName = fancyName;
}
}
You really have all the benefits without any drawback.
I want to define a default value for an Enum class. The idea of my enum is to define a few specific String values and tie them to enumerations. However, if a user provide an String that I am not expecting, I want the enum to reflect an invalid state. Consider
public class EnumDemo {
public enum Food {
HAMBURGER("h"), FRIES("f"), HOTDOG("d"), ARTICHOKE("a"), INVALID("invalid");
Food(String code) {
this.code = code;
}
private final String code;
public String getCode() {
return code;
}
public static Food fromString(String value) {
return Arrays.stream(Food.values()).filter(s -> s.code.equalsIgnoreCase(value)).findFirst()
.orElse(Food.INVALID);
}
}
public static void main(String[] args) {
Food f1 = Food.fromString("h");
System.out.println(f1 + " " + f1.getCode());
f1 = Food.fromString("x");
System.out.println(f1 + " " + f1.getCode());
}
}
this prints out
HAMBURGER h
INVALID invalid
The problem here is that I am defining the string for the code. invalid is hardcoded as per
INVALID("invalid")
Is it possible to make this a variable? So that I can keep track of what the invalid input was? I tried
INVALID(String x)
but obviously got a syntax exception. Would it just be better not to use an enum?
Lastly, the reason I want to keep track of invalid inputs is that in the future, I want the flexibility to change the enum depending on the users.
You could create a wrapper to stash the original input:
public class FoodInput {
private final Food food;
private final String input;
public FoodInput(String input) {
this.food = Food.fromString(input);
this.input = input;
}
public Food getFood() {
return food;
}
public String getInput() {
return input;
}
}
Im making a Coin class with a static arraylist that stores every instance of the class created, howevered I need to initiate that list with an initial instance, and I have not figured out how to do it without adding it twice (because of a redundant code), any suggestions?
public class Coin {
private static ArrayList<String> coinNames = new ArrayList<>();
private static ArrayList<String> coinAbbreviations = new ArrayList<>(Arrays.asList("CLP"));
private static ArrayList<Coin> coins =
new ArrayList<>(Arrays.asList(new Coin("Pesos chilenos", "CLP", 1f, "CLP")));
private static HashMap<String,Float> exchangeRates;
private String coinName;
private String coinAbbreviation;
private Float coinValue;
private String unit;
public Coin(String coinName, String coinAbbreviation, Float coinValue, String unit) {
assert !coinAbbreviations.contains(coinAbbreviation) : "Coin abbreviation already used";
assert coinAbbreviations.contains(unit) : "Coin unit non existent.";
assert !coinNames.contains(coinName) : "Coin name already used.";
this.coinName = coinName;
this.coinAbbreviation = coinAbbreviation;
this.coinValue = coinValue;
this.unit = unit;
coins.add(this);
}
}
If you insist on having mutable static variables at all -- it's generally not a good idea to do things like this at all -- you could do
private static ArrayList<Coin> coins =
new ArrayList<>();
static {
new Coin("Pesos chilenos", "CLP", 1f, "CLP");
}
...which adds the element to the list immediately.
What stops you initialising your list in its declaration and then just adding each instance to the list in the constructor?
You could alternatively design your application using some best-practice patterns. You want to keep a registry of all created coins. This is best kept outside of the Coin class itself. You could have a class that manages the creation of coins and keeps a list of those that it created. The Coin class itself can be an interface, if you like, as that way you ensure that it cannot be created other than by the CoinFactory.
public interface Coin {
String name();
String abbreviation();
BigDecimal value();
String unit();
}
And the Coin factory class:
public class CoinFactory {
// Concrete coin is an internal implementation class whose details don't
// need to be known outside of the CoinFactory class.
// Users just see it as interface Coin.
private static class ConcreteCoin implements Coin {
private final String name;
private final String abbreviation;
private final BigDecimal value;
private final String unit;
ConcreteCoin(String name, String abbreviation, BigDecimal value, String unit) {
this.abbreviation = abbreviation;
this.name = name;
this.value = value;
this.unit = unit;
}
public String name() { return name; }
public String abbreviation() { return abbreviation; }
public BigDecimal value() { return value; }
public String unit() { return unit; }
}
// Sets for enforcing uniqueness of names and abbreviations
private Set<String> names = new HashSet<>();
private Set<String> abbreviations = new HashSet<>();
// All coins must have one of the following ISO currency codes as the 'unit' field.
private final Set<String> allIsoCurrencyCodes =
Set.of("CLP", "GBP", "EUR", "CAD", "USD", "XXX" /* , ... */);
private List<Coin> allCoins = new ArrayList<>(
List.of(createCoin("Pesos chilenos", "CLP", BigDecimal.ONE, "CLP")));
private List<Coin> unmodifiableListOfAllCoins =
Collections.unmodifiableList(allCoins);
public Coin createCoin(String name, String abbreviation, BigDecimal value, String unit) {
if (!names.add(name))
throw new IllegalArgumentException("Name already exists: " + name);
if (!abbreviations.add(abbreviation))
throw new IllegalArgumentException("Abbreviation already exists: " + abbreviation);
if (!allIsoCurrencyCodes.contains(unit))
throw new IllegalArgumentException("Coin unit is not a recognised ISO currency code: " + unit);
Coin coin = new ConcreteCoin(name, abbreviation, value, unit);
allCoins.add(coin);
return coin;
}
public Collection<Coin> allCoins() {
return unmodifiableListOfAllCoins;
}
}
I'm writing a library, which has a predefined set of values for an enum.
Let say, my enum looks as below.
public enum EnumClass {
FIRST("first"),
SECOND("second"),
THIRD("third");
private String httpMethodType;
}
Now the client, who is using this library may need to add few more values. Let say, the client needs to add CUSTOM_FIRST and CUSTOM_SECOND. This is not overwriting any existing values, but makes the enum having 5 values.
After this, I should be able to use something like <? extends EnumClass> to have 5 constant possibilities.
What would be the best approach to achieve this?
You cannot have an enum extend another enum, and you cannot "add" values to an existing enum through inheritance.
However, enums can implement interfaces.
What I would do is have the original enum implement a marker interface (i.e. no method declarations), then your client could create their own enum implementing the same interface.
Then your enum values would be referred to by their common interface.
In order to strenghten the requirements, you could have your interface declare relevant methods, e.g. in your case, something in the lines of public String getHTTPMethodType();.
That would force implementing enums to provide an implementation for that method.
This setting coupled with adequate API documentation should help adding functionality in a relatively controlled way.
Self-contained example (don't mind the lazy names here)
package test;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<HTTPMethodConvertible> blah = new ArrayList<>();
blah.add(LibraryEnum.FIRST);
blah.add(ClientEnum.BLABLABLA);
for (HTTPMethodConvertible element: blah) {
System.out.println(element.getHTTPMethodType());
}
}
static interface HTTPMethodConvertible {
public String getHTTPMethodType();
}
static enum LibraryEnum implements HTTPMethodConvertible {
FIRST("first"),
SECOND("second"),
THIRD("third");
String httpMethodType;
LibraryEnum(String s) {
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
static enum ClientEnum implements HTTPMethodConvertible {
FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
String httpMethodType;
ClientEnum(String s){
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
}
Output
first
POST
Enums are not extensible. To solve your problem simply
turn the enum in a class
create constants for the predefined types
if you want a replacement for Enum.valueOf: track all instances of the class in a static map
For example:
public class MyType {
private static final HashMap<String,MyType> map = new HashMap<>();
private String name;
private String httpMethodType;
// replacement for Enum.valueOf
public static MyType valueOf(String name) {
return map.get(name);
}
public MyType(String name, String httpMethodType) {
this.name = name;
this.httpMethodType = httpMethodType;
map.put(name, this);
}
// accessors
public String name() { return name; }
public String httpMethodType() { return httpMethodType; }
// predefined constants
public static final MyType FIRST = new MyType("FIRST", "first");
public static final MyType SECOND = new MyType("SECOND", "second");
...
}
Think about Enum like a final class with static final instances of itself. Of course you cannot extend final class, but you can use non-final class with static final instances in your library. You can see example of this kind of definition in JDK. Class java.util.logging.Level can be extended with class containing additional set of logging levels.
If you accept this way of implementation, your library code example can be like:
public class EnumClass {
public static final EnumClass FIRST = new EnumClass("first");
public static final EnumClass SECOND = new EnumClass("second");
public static final EnumClass THIRD = new EnumClass("third");
private String httpMethodType;
protected EnumClass(String name){
this.httpMethodType = name;
}
}
Client application can extend list of static members with inheritance:
public final class ClientEnum extends EnumClass{
public static final ClientEnum CUSTOM_FIRST = new ClientEnum("custom_first");
public static final ClientEnum CUSTOM_SECOND = new ClientEnum("custom_second");
private ClientEnum(String name){
super(name);
}
}
I think that this solution is close to what you have asked, because all static instances are visible from client class, and all of them will satisfy your generic wildcard.
We Fixed enum inheritance issue this way, hope it helps
Our App has few classes and each has few child views(nested views), in order to be able to navigate between childViews and save the currentChildview we saved them as enum inside each Class.
but we had to copy paste, some common functionality like next, previous and etc inside each enum.
To avoid that we needed a BaseEnum, we used interface as our base enum:
public interface IBaseEnum {
IBaseEnum[] getList();
int getIndex();
class Utils{
public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
if (index + 1 < list.length) {
return list[index + 1];
} else if(isCycling)
return list[0];
else
return null;
}
public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
IBaseEnum previous;
if (index - 1 >= 0) {
previous = list[index - 1];
}
else {
if (isCycling)
previous = list[list.length - 1];
else
previous = null;
}
return previous;
}
}
}
and this is how we used it
enum ColorEnum implements IBaseEnum {
RED,
YELLOW,
BLUE;
#Override
public IBaseEnum[] getList() {
return values();
}
#Override
public int getIndex() {
return ordinal();
}
public ColorEnum getNext(){
return (ColorEnum) new Utils().next(this,false);
}
public ColorEnum getPrevious(){
return (ColorEnum) new Utils().previous(this,false);
}
}
you could add getNext /getPrevious to the interface too
#wero's answer is very good but has some problems:
the new MyType("FIRST", "first"); will be called before map = new HashMap<>();. in other words, the map will be null when map.add() is called. unfortunately, the occurring error will be NoClassDefFound and it doesn't help to find the problem. check this:
public class Subject {
// predefined constants
public static final Subject FIRST;
public static final Subject SECOND;
private static final HashMap<String, Subject> map;
static {
map = new HashMap<>();
FIRST = new Subject("FIRST");
SECOND = new Subject("SECOND");
}
private final String name;
public Subject(String name) {
this.name = name;
map.put(name, this);
}
// replacement for Enum.valueOf
public static Subject valueOf(String name) {
return map.get(name);
}
// accessors
public String name() {
return name;
}
I have following homework about computer store:
There are several class include: Monitor, Case, Mouse, Keyboard.
All the classes have common fields: id, name, price, quantity.
Each class has some unique fields.
All most features are: add, update, delete, find, show list, save, load file
-So, first I will create a class named Product have 4 common fields. Above classes will extends from Product.
-Then, I think I maybe create a ComputerStore class which have a field is items type ArrayList. items stores all objects which are instance of 4 above classes But I'm not sure.
Whether it is reasonable? I need some ideas
Before , I always use ArrayList store for only one class like
List <String> list = new ArrayList<String>();
Now they are multi type. I think it's generic in Java, right??
In case, I want to update for 1 items. I must think about how to change information for them. Ex: mouse for some code, keyboard for another code. Anyway, thank for everybody!
Your approach is 100% reasonable.
You are completely on the right track with "generics". First, check out the official enter link description here.
Next, just think about your data in real world terms, like you are already doing: Monitor, case, mouse, and keyboard are products. Your computer store's inventory is a list of products.
Hint: A list of products.
Put that together with what you learn about generics through that tutorial, and you'll be good to go.
You could use java generic.First create a java collection (ex: List) with supper class type, Product. Now you could add any sub classes (Monitor , Keyboard etc) in your collection (List) that extends of class Product.
public class Product{
}
public class Monitor extends Product{
}
public class Keyboard extends Product{
}
List<Product> products = new ArrayList<Product>();
products.add(new Monitor());
products.add(new Keyboard());
Since you have a superclass (Product), you can have the list's type as Product, i.e.
List<Product> list = new ArrayList<Product>();
list.add(new Mouse());
list.add(new Keyboard());
It will allow you to iterate them and list their name and price without caring for the class, but if you intend to take an item out of the list you'll need to check its actual type (depending on what you do with it).
You can do like below
import java.util.List;
import java.util.ArrayList;
class Test{
public static void main(String... args){
List<MultiObj> multiObjs = new ArrayList();
MultiObj ob = new MultiObj(); multiObjs.add(ob);
ResX xOb = new ResX(); multiObjs.add(xOb);
ResY yOb = new ResY(); multiObjs.add(yOb);
ResZ zOb = new ResZ(); multiObjs.add(zOb);
for (int i = 0; i < multiObjs.size(); i++ ) {
System.out.println(multiObjs.get(i).getV());
}
System.out.println("Waoo its working");
}
}
class MultiObj{
public String greet(){
return "Hello World";
}
public String getV(){
return "Hello World";
}
}
class ResX extends MultiObj{
String x = "ResX";
public String getX(){
return x;
}
public String getV(){
return x;
}
}
class ResY extends MultiObj{
String y = "ResY";
public String getY(){
return y;
}
public String getV(){
return y;
}
}
class ResZ extends MultiObj{
String z = "ResZ";
public String getZ(){
return z;
}
public String getV(){
return z;
}
}
You could do this:
public class Item {
public Item(int id, string name, float price, int amount, int ArrayID) {
if (ArrayID == 1) {
ID1 = id;
name1 = name;
price1 = price;
amount1 = amount;
}
if (ArrayID == 2) {
ID2 = id;
name2 = name;
price2 = price;
amount2 = amount;
}
if (ArrayID == 3) {
ID3 = id;
name3 = name;
price3 = price;
amount3 = amount;
}
if (ArrayID == 4) {
ID4 = id;
name4 = name;
price4 = price;
amount4 = amount;
}
}
//ArrayID #1
public static int ID1;
public static String name1;
public static float price1;
public static int amount1;
//ArrayID #2
public static int ID2;
public static String name2;
public static float price2;
public static int amount2;
//ArrayID #3
public static int ID3;
public static String name3;
public static float price3;
public static int amount3;
//ArrayID #4
public static int ID4;
public static String name4;
public static float price4;
public static int amount4;
public static int[] id = ID1, ID2 ID3, ID4;
//so forth...
}