I decided to get into more JAVA and I noticed in OCA 7 that an enum can declare a method which overrides another method. See this enum:
enum CoffeeSize {
BIG(),
HUGE(),
OVERWHELMING() {
public String getLidCode() { // This method overrides the following method with similar name.
return 'A';
}
}; // <--- is this semicolon I should be looking for?
CoffeeSize(ounces) {
this.ounces = ounces;
}
private int ounces;
public int getOunces() {
return ounces;
}
public String getLidCode() {
return 'B';
}
}
My question is in which case does a method in a enum override another method. Is it the method preceding the semicolon that overrides or what's the rule here?
Thanks for your time.
The constants act similar to anonymous classes, where the enum itself is the abstract base class:
abstract class CoffeeSize {
CoffeeSize(int ounces) {
this.ounces = ounces;
}
private int ounces;
public int getOunces() {
return ounces;
}
public String getLidCode() {
return "B";
}
}
CoffeeSize OVERWHELMING = new CoffeeSize(3) {
#Override
public String getLidCode() {
return "A";
}
};
You can override the base implementation with any constant, not just the one before the semicolon:
enum CoffeeSize {
BIG(1){
#Override
public String getLidCode() {
return "C";
}
},
HUGE(2) {
#Override
public String getLidCode() {
return "B";
}
},
OVERWHELMING(3) {
#Override
public String getLidCode() {
return "A";
}
};
...
}
In the above, all the constants override getLidCode with a different implementation. The semicolon just marks the end of the list of constants.
Related
I am trying to achieve something like the below?
abc.java
public enum ABC {
A("a"),
B("b"),
C("c")
}
numarical.java
public enum num {
One("1"),
Two("2"),
Three("3")
}
DetectEnum.java
public class DetectEnum {
ABC abc_enum;
num 123_enum;
public **<?>** getEnum(String lang) {
switch (lang) {
case "Alpha" :
alpha();
break;
default :
numaric();
break;
}
}
public ABC alpha() {
return abc_enum;
}
public num numaric() {
return 123_enum;
}
}
what we can have in the place of this <?> , meaning what should be the return type here?
I have two classes: Fish and Plant. They do not inherit from any classes.
But both of them have one method called isAlive() which have the same implementation details. Now I have a list of fish and another list of dog and I need to remove dead fish and dead dog. I want my method to have same name but it is not possible without adding additional field to method signature. Is it possible I do not need to write additional chunk of code which does the same as the last chunk of code?
Below is the code. For class Model, Fish and Plant are two data members and they are ArrayList of Fish and Plant objects.
Is there any way I can write only one method called count and I do not need to add additional field to my method signature or modify my return type?
public class Fish{
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Plant{
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Model{
private int countDeadFish() {
int totalCount = 0;
for(Fish aFish : this.fish) {
if(aFish.isAlive() == false) {
totalCount += 1;
}
}
return totalCount;
}
private int countDeadPlants() {
int totalCount = 0;
for(Plant plant : this.plants) {
if(plant.isAlive() == false) {
totalCount += 1;
}
}
return totalCount;
}
}
If you do not want to use inheritance, then you can use a common method:
public class AliveChecker {
public static boolean isAlive(int size) {
return size > 0;
}
}
public class Plant{
public boolean isAlive(){
return AliveChecker.isAlive(this.size);
}
}
public class Fish{
public boolean isAlive(){
return AliveChecker.isAlive(this.size);
}
}
Since Fishand Plant do not inherit from anything yet you can consider creating a superclass and extend from it:
public class LivingThing {
protected int size = 1;
public boolean isAlive() {
return size > 0;
}
}
public class Plant extends LivingThing {
}
public class Fish extends LivingThing {
}
This example uses inheritance to classify Plantand Fish into the superclass LivingThing. You can set the size for example in the constructor of the Plant or an instance method:
public class Plant extends LivingThing {
public Plant(int size){
this.size = size;
}
}
Your Model could then be:
public class Model{
private int countDeadFish() {
return countDead(this.fish);
}
private int countDeadPlants() {
return countDead(this.plants);
}
private int countDead(ArrayList<LivingThing> things) {
int totalCount = 0;
for(LivingThing thing: things) {
if(!thing.isAlive()) {
totalCount++;
}
}
return totalCount;
}
}
Use interface
public interface LiveObject {
boolean isAlive();
}
public class Fish implements LiveObject {
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Plant implements LiveObject {
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Model{
private int countDead(Collection<LiveObject> objects) {
int totalCount = 0;
for(LiveObject obj : objects) {
if(obj.isAlive() == false) {
totalCount += 1;
}
}
return totalCount;
}
private int countDeadFish() {
return countDead(this.fish);
}
}
Based on the comments it seems you can't modify Fish or Plant. Here's an approach to reduce duplication in countDead<Something> methods which does not require this.
Basically you want to count items in an array which satisfy certain criteria. With Java 8 you can capture this criteria in a predicate using lambdas or method references. You do not need inheritance or implementation of a certain interface for this.
private long countDeadFish() {
return countDeadItems(this.fish, Fish::isAlive);
}
private long countDeadPlants() {
return countDeadItems(this.plants, Plant::isAlive);
}
private <T> long countDeadItems(Collection<T> items, Predicate<? super T> isAlive) {
return items.stream().filter(isAlive.negate()).count();
}
You could create a utility method (in a utility class somewhere):
public final class Liveliness {
private Liveliness() {
}
public static boolean isAlive(final IntSupplier sizer) {
return sizer.getAsInt() > 0;
}
}
Your method then becomes:
public boolean isAlive(){
return Liveliness.isAlive(this::getSize);
}
Alternatively, use an interface Life:
public interface Life {
int getSize();
default boolean isAlive(){
return getSize() > 0;
}
}
This way, adding a getSize method and inheriting from Life will add the method.
Note, avoid the following antipattern:
if(test) {
return true;
} else {
return false;
}
Use return test.
I have two classes that do the same things but by the different ways. I need to create an object of one of these classes depending on config settings. Here is a brief example of what do I want to do.
public class A {
public string getLetter() {
return "A";
}
}
public class B {
public string getLetter() {
return "B";
}
}
public class MainActivity {
private myObject; // How to declare it in my case?
private int config = 0;
public void onCreate(Bundle savedInstanceState) {
if (config == 0) {
myObject = new A();
} else {
myObject = new B();
}
String letter = myObject.getLetter();
}
}
Actually everything is much more complex. Each of classes A and B asynchronously listens to the different sources of data, converts it to the format that can be used in further processing and passes it to MainActivity. Depending on configuration only one source of data must be selected. How can I do this? Variant with
letter = A.getLetter();
will not work.
This should work:
public class A {
public String getLetter() {
return "A";
}
}
public class B {
public String getLetter() {
return "B";
}
}
public class MainActivity {
private int config = 0;
public void onCreate(Bundle savedInstanceState) {
String letter="";
if (config == 0) {
A myObject = new A();
letter = myObject.getLetter();
} else {
B myObject = new B();
letter = myObject.getLetter();
}
}
}
Use interface or abstract class and implement or extend it in class A and B, e.g.
public interface Letter {
String getLetter();
}
public class A implements Letter {
public String getLetter() {
return "A";
}
}
public class B implements Letter {
public String getLetter() {
return "B";
}
}
// Then you can declare and use it as interface
private Letter myObject;
// init logic
...
String letter = myObject.getLetter();
How can I return enums like this?
Before I was returing an int with 0 if no, 1 if yes and 2 if other. But this wasn't good way to do. So how should it be done. My code:
class SomeClass{
public enum decizion{
YES, NO, OTHER
}
public static enum yourDecizion(){
//scanner etc
if(x.equals('Y')){
return YES;
}
else if (x.equals('N')){
return NO;
}
else{
return OTHER;
}
}
}
I don't what the "//scanner etc." does, but the methods return type should be decizion:
public static decizion yourDecizion() { ... }
Furthermore, you can add the Y, N, etc. values to the enum constants:
public enum decizion{
YES("Y"), NO("N"), OTHER;
String key;
decizion(String key) { this.key = key; }
//default constructor, used only for the OTHER case,
//because OTHER doesn't need a key to be associated with.
decizion() { }
static decizion getValue(String x) {
if ("Y".equals(x)) { return YES; }
else if ("N".equals(x)) { return NO; }
else if (x == null) { return OTHER; }
else throw new IllegalArgumentException();
}
}
Then, in the method, you can just do:
public static decizion yourDecizion() {
...
String key = ...
return decizion.getValue(key);
}
I think you should do something like these, an enum class. Then you can add as many types you want and the method yourDecizion() will return the enum type depending on the given parameter.
public enum SomeClass {
YES(0),
NO(1),
OTHER(2);
private int code;
private SomeClass(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static SomeClass yourDecizion(int x) {
SomeClass ret = null;
for (SomeClass type : SomeClass.values()) {
if (type.getCode() == x)
ret = type;
}
return ret;
}
}
Change your code to:
class SomeClass{
public enum decizion {
YES, NO, OTHER
}
public static decizion yourDecizion(){
//scanner etc
if(x.equals('Y')){
return decizion.YES;
}
else if (x.equals('N')){
return decizion.NO;
}
else{
return decizion.OTHER;
}
}
}
Note: The method return type must be decizion instead of enum and decizion should have an upper case name (as all classes should).
You can get the value in below way. Here you have private constructor which will initialize the value you want to set and when the instance method value gets invoked simply return this.key.
public class Application {
enum Day {
MONDAY("Monday"), TUESDAY("Tuesday");
String key;
Day(String str) {
key = str;
}
public String value() {
return this.key;
}
}
public static void main(String[] args) {
System.out.println(Day.MONDAY.value());
}
}
I am using enumeration with switch case but I am getting the following error:
NEWS FEED is not a constant in FragmentName
This is my enum string constant,
public enum FragmentName{
FRAGMENT_NEWSFEED("NEWS FEED"),
FRAGMENT_MESSAGES("MESSAGES"),
FRAGMENT_EVENTS("EVENTS"),
FRAGMENT_WHOISAROUDNME("WHOS AROUND");
private final String text;
private FragmentName(final String text) {
this.text = text;
}
#Override
public String toString() {
return text;
}
}
//This is my function from where i check for corresponding enum constant
public void changeTitle(String title) {
switch (Enums_String.FragmentName.valueOf(title)) {
case FRAGMENT_NEWSFEED:
System.out.println("1");
break;
case FRAGMENT_EVENTS:
System.out.println("2");
break;
case FRAGMENT_MESSAGES:
System.out.println("3");
break;
case FRAGMENT_WHOISAROUDNME:
System.out.println("4");
break;
}
}
When I call
changeTitle("NEWS FEED");
it creates an exception in the changeTitle function even the value passed is same, so any help would be appreciated as I have tried my every effort to solve this.
Add this code to your enum
private static final Map<String, FragmentName> map = new HashMap<>();
static {
for (FragmentName en : values()) {
map.put(en.text, en);
}
}
public static FragmentName valueFor(String name) {
return map.get(name);
}
Now instead of valueOf use valueFor
switch (Enums_String.FragmentName.valueFor(title))
// ^^^^^^^^
The valueOf
Returns the enum constant of the specified enum type with the
specified name. The name must match exactly an identifier used to
declare an enum constant in this type. (Extraneous whitespace
characters are not permitted.
What you want do id get the enum by a member value for that you have write a function to do so like fromString below
public enum FragmentName {
FRAGMENT_NEWSFEED("NEWS FEED"),
FRAGMENT_MESSAGES("MESSAGES"),
FRAGMENT_EVENTS("EVENTS"),
FRAGMENT_WHOISAROUDNME("WHOS AROUND");
private final String text;
private FragmentName(final String text) {
this.text = text;
}
#Override
public String toString() {
return text;
}
public static FragmentName fromString(String value) {
for (FragmentName fname : values()) {
if (fname.text.equals(value)) {
return fname;
}
}
return null;
}
}
and replace your switch case like
switch (FragmentName.fromString(title)) {
Create a method like this :
public static FragmentName getFragmentNameByText(String text) {
for (FragmentName fragment : values()) {
if (fragment.text.equals(text)) {
return fragment;
}
}
return null;
}
and call this instead of valueOf().
You can change your function to compare the string values passed in:
public void changeTitle(String title) {
if(title.equals(FRAGMENT_NEWSFEED.toString())) {
System.out.println("1");
} else if(title.equals(FRAGMENT_MESSAGES.toString())) {
System.out.println("2");
} else if(title.equals(FRAGMENT_EVENTS.toString())) {
System.out.println("3");
} else if(title.equals(FRAGMENT_WHOISAROUDNME.toString())) {
System.out.println("4");
} else {
// throw an error
}
}
You can't operate an switch off of a function call, so you have to use an if-else block.