Im going to go straight to the point.
I got 3 classes. Person, Professor and Student. (Persona, Profesor, Alumno).
Both professor and student extends from Person. But Person can also be instantiated, because it's not abstract.
I have 50 persons, randomly generated on a list. It can be any kind, person professor or student.
I want to separate them each into a different list.
At the moment, I did this:
for(Persona persona : personas) {
if(persona instanceof Profesor) {
profesores.add((Profesor) persona);
}
else if(persona instanceof Alumno) {
alumnos.add((Alumno) persona);
}
else {
nuevasPersonas.add(persona);
}
}
profesores is a list of Professor
alumnos is a list of Students
nuevasPersonas is a list of Persons
Which works perfect. But I was told not to use instanceof, so I don't get used to it.
Any ideas on how to separate them into lists, without the use of instanceof?
Thanks.
I would use instanceof, why wouldn't you want to get used to it?
Anyway, an alternative could be having a variable type (with getter, but no setter), in Person (=0), and override it to 1 and 2 in Professor and Student.
Then,you would test the variable instead of using instanceof.
Perhaps your teacher wants you to create an overriden method which answers the question isStudent or isProfessor?
However, since this gives us no extra information that is not already available via the instanceof operator, this is a contrived example where adding these redundant methods is not really a great design decision. Unfortunately in beginner classes you will sometimes encounter such contrived examples which are overly simplified for the purpose of teaching a particular language concept.
You can overload an "add" method with each of the object types - something like the following code.
The main method just adds instances of three different Objects to the ObjectSplitter class - it separates them out in to different Collections
public class ObjectSplitter {
public static void main(String ... args){
ObjectSplitter d = new ObjectSplitter();
d.addToCollection(new Object1());
d.addToCollection(new Object1());
d.addToCollection(new Object2());
d.addToCollection(new Object1());
d.addToCollection(new Object1());
d.addToCollection(new Object1());
d.addToCollection(new Object2());
d.addToCollection(new Object3());
d.addToCollection(new Object1());
System.out.println("Num Ob1s : " + d.getOb1sSize());
System.out.println("Num Ob2s : " + d.getOb2sSize());
System.out.println("Num Ob3s : " + d.getOb3sSize());
}
private List<Object1> ob1s = new ArrayList<>();
private List<Object2> ob2s = new ArrayList<>();
private List<Object3> ob3s = new ArrayList<>();
void addToCollection(Object1 o){
ob1s.add(o);
}
void addToCollection(Object2 o){
ob2s.add(o);
}
void addToCollection(Object3 o){
ob3s.add(o);
}
int getOb1sSize(){
return ob1s.size();
}
int getOb2sSize(){
return ob2s.size();
}
int getOb3sSize(){
return ob3s.size();
}
static class Object1 {
}
static class Object2 extends Object1 {
}
static class Object3 extends Object2 {
}
}
also you can use getClass().getSimpleName() as below:
public static void main (String[] args) throws java.lang.Exception
{
List<Test1> list = new ArrayList<>(2);
Test1 o1 = new Test1();
list.add(o1);
Test2 o2 = new Test2();
list.add(o2);
for (Test1 test : list) {
System.out.println(test.getClass().getSimpleName());
}
}
static class Test1{
}
static class Test2 extends Test1{
}
in the for loop you can have a if condition as like as below code to do your job:
for (Test1 test : list) {
String className = test.getClass().getSimpleName();
if(className.equals("Test1")) {
System.out.println("Test1");
} else if(className.equals("Test2")) {
System.out.println("Test2");
}
System.out.println();
}
another solution according to overriding methods is:
public static void main (String[] args) throws java.lang.Exception
{
List<Test1> list = new ArrayList<>(2);
Test1 o1 = new Test1();
list.add(o1);
Test2 o2 = new Test2();
list.add(o2);
for (Test1 test : list) {
test.addToMyTypeList();
}
for(Test1 test : Test1.list) {
System.out.println(test.getClass().getSimpleName());
}
for(Test1 test : Test1.list) {
System.out.println(test.getClass().getSimpleName());
}
}
static class Test1{
public static List<Test1> list = new ArrayList<>();
public void addToMyTypeList() {
String className = test.getClass().getSimpleName();
if(className.equals("Test1")) {
Test1.list.add(this);
}
}
}
static class Test2 extends Test1{
public static List<Test1> list = new ArrayList<>();
#Override
public void addToMyTypeList() {
String className = test.getClass().getSimpleName();
if(className.equals("Test2")) {
Test2.list.add(this);
}
}
}
Related
I have an array of objects of classes Car, Bicycle, and Van. I want to iterate through all objects and execute the go() method. go() for one class looks like this.
public class Van extends Vehicle {
#Override
public void go() {
System.out.println("Van started");
}
}
Each of these classes inherits the Vehicle class. So, when I initialized an array of type Vehicle[], it worked without a problem.
Now I want to do the same with an array of Object[]. But as the objects are of different types, I get an error asking to cast the x to the relevant datatype (in this case Car, Van, or Bicycle). I tried using the x.getClass() but it gives me answers as class Car, class Bicycle, etc. When I try to execute go() method, I get an error saying The method go() is undefined for the type Class<capture#3-of ? extends Object>
public class App {
public static void main(String[] args) throws Exception {
Car car = new Car();
Bicycle bicycle = new Bicycle();
Van van = new Van();
Object[] racers = {car, bicycle, van};
for(Object x : racers) {
System.out.println(x.getClass());
x.getClass().go(); // error - The method go() is undefined for the type Class<capture#3-of ? extends Object>
}
}
}
Found the answer
public class App {
public static void main(String[] args) throws Exception {
Car car = new Car();
Bicycle bicycle = new Bicycle();
Van van = new Van();
Object[] racers = {car, bicycle, van};
for(Object x : racers) {
System.out.println(x.getClass());
((Vehicle) x).go(); // this is the only change I made
}
}
}
The following would have worked
Vehicle[] racers = {car, bicycle, van};
for (Vehicle x : racers) { ... x.go();
Dynamic detection does works too. You could use the modern Stream<?>.
Object[] racers = {car, bicycle, van};
Arrays.stream(racers)
.filter(r -> r instanceOf(Vehicle)
.map(Vehicle.class::cast)
.forEach(r -> {
r.go(); ...
};
You have to use the "instanceof" keyword
Object o = "testString";
if (o instanceof Integer) {
System.out.println("is Integer");
return
}
if (o instanceof String) {
System.out.println("is String");
return;
}
Here is Demo class
public class Demo {
int i;
String s;
}
I have an instance of Demo:
Demo demo = new Demo(1, "hello");
How can I get demo field values as array of Object like:
Object[] {1, "hello"};
Updated:
For new Object[] {demo.i, demo.s} I need know fields from Demo, however I need a general way to get Object array for any class that has primitive fields and/or simple fields.
you will need to make it yourself indeed. To get it how you showed, you will want a getter method in your object
public class Demo(){
int i;
String s;
public Demo(){
//constructor
}
public Object[] getDemo{
return new Object[] {i, s};
}
}
As stated in the comments, you can do it via reflection quite easily:
public static Object[] getFieldValues(Object o) {
return Arrays.stream(o.getClass().getDeclaredFields())
.map(field -> {
try {
return field.get(o);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
})
.toArray();
}
public static void main(String[] args) {
class Demo {
int i;
String s;
}
Demo d = new Demo();
d.i = 1;
d.s = "hello";
Object[] fieldValues = getFieldValues(d);
System.out.println(Arrays.toString(fieldValues));
}
However, also as stated in the comments, this might be an "X-Y problem" and there may be better solutions to what you are actually looking to achieve.
Every time I call the method inserimentoVoto to add elements in a list contained in the object Studente, the data is overwritten I know it's easy but I just started to code.
public class Run {
public static void main(String[] args) {
Gestione g = new Gestione();
Studente s = new Studente();
g.inserimentoVoto(s);
}
}
This is the method
public void inserimentoVoto(Studente s) {
Voto v = new Voto();
System.out.println("Insert value");
v.setVoto(scanner.next());
System.out.println("Insert name");
v.setMateria(scanner.next());
v.setDataVoto(new Date());
s.setListaVoti(new ArrayList<Voto>());
s.getListaVoti().add(v);
}
s.setListaVoti(new ArrayList<Voto>());
You are creating a new ArrayList everytime
The above line should be only done once in the Studente class.
public class Studente
{
private ArrayList<Voto> arr = new ArrayList<Voto>();
... Other data ...
public ArrayList<Voto> getListaVoti()
{
return arr;
}
... Other methods ...
}
You do not need a setListaVoti at all - because it's done only once.
In the inserimentoVoto method, you only need
s.getListaVoti().add(v);
I'm just getting into testing of code. I have done unit tests before but haven't really isolated them. So they were more like integration test (indirectly). I want to give Mockito a try and I have added it to my Intellij IDE.
But I have no idea of how to actually implement mocking at all. There are examples on their website but I just can't wrap my head around the concept of mocking. I know that one uses mocking to isolate the unit testing to ensure that the errors are in the unit itself and not in a dependency.
I wrote the following:
#Test
public void testChangeMemberReturnsTrue() throws Exception {
Member tempMem = new Member();
tempMem.setMemberFirstName("Swagrid");
tempMem.setMemberLastName("McLovin");
tempMem.setMemberID("SM666");
SQLDUMMY.saveMember(tempMem); //Save member to dummy DB.
Member checkMem = new Member();
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) { // Look through all saved members
if (m.equals(tempMem)) { // If match, save to checkMem
checkMem = m;
}
}
assertTrue(tempMem.equals(checkMem)); // Make sure they are really equal.
String newfirstname = "Darius";
String newlastname = "DunkMaster";
assertTrue(memhandling.changeMember(tempMem, newfirstname, newlastname));
}
And here is the actual method:
public boolean changeMember(Member mem, String n1, String n2) {
try {
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) {
if (m.equals(mem)) {
m.setMemberFirstName(n1);
m.setMemberLastName(n2);
m.setMemberID(ensureUniqueID(m, m.getMemberID())); //Just a method call to another method in the same class to ensure ID uniqueness.
return true;
}
else {
return false;
}
}
}
catch (Exception e) {
System.out.println("Error4.");
}
return false;
}
I'd like to mock the SQLDUMMY (Which I created just to see if my tests would pass at all, which they do.) The SQLDUMMY class looks like this:
public class SQLDUMMY {
private static ArrayList<Member> memberList = new ArrayList<>();
private static ArrayList<Ship> shipList = new ArrayList<>();
public static ArrayList<Member> getAllMembers() {
return memberList;
}
public static void saveMember(Member m) {
memberList.add(m);
}
public static void deleteMember(Member memIn) {
memberList.remove(memIn);
}
public static void saveShip(Ship newShip) {
shipList.add(newShip);
}
public static ArrayList<Ship> getAllShips() {
return shipList;
}
public static void deleteShip(Ship s) {
shipList.remove(s);
}
}
It basically just consists of getters and add/remove for the ArrayLists that act as a contemporary DB storage.
Summary: How can I mock the SQLDUMMY class (DAO), so it is no longer a dependency for the Unit tests?
You need to read on how Mockito works.
The basic idea is that it extends you class and and overrides all methods and allows you to return what ever you want it too.
Syntax is :
SQLDummy sqlDummy = Mockito.mock(SQLDummy.class);
Mockito.when(sqlDummy.getAllShips()).thenReturn(new ArrayList< Ship >())
I have an issue with one of my class. I'm using a "varargs" constructor for unknown number of parameter.
public Groupe(String...nom){
for(String item:nom){
this.nom.add(item.toLowerCase());
}
}
public Groupe(String nom){
String[] list =nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The first constructor is called...that's fine, but there is a conflict when passing only ONE parameter with the second contructor. I would like to use the second constructor when passing only one string, and the first if 2 and more parameters.
I'd want to handle this
new Groupe("Foo,Bar");
This is where I call it. I suspect the "error" comes from there
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
I don't pass a String, but a Varargs (tab?)...
It should be fine, with the caveat that null can be converted to either String[] or String:
public class Test {
public Test(String single) {
System.out.println("Single");
}
public Test(String... multiple) {
System.out.println("Multiple");
}
public static void main(String[] args) {
new Test("Foo"); // Single
new Test("Foo", "Bar"); // Multiple
new Test(); // Effectively multiple
// new Test(null); // Doesn't compile - ambiguous
new Test((String) null); // Single
}
}
EDIT: Now that you've shown us the calling code, that's definitely the problem:
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
Here, the type of nom is String[] - so it will always call the first constructor. You've got an array of strings there - under what circumstances do you want to call the second constructor?
To be honest, given that the two constructors act significantly differently, I would actually make both constructors private, and provide static methods:
public static Groupe fromStringArray(String... nom)
public static Groupe fromCommaSeparatedString(String nom)
Then it will be absolutely clear what you're expecting in each case.
Maybe this can be a solution:
public Groupe(String...nom){
if (nom.length == 1) {
add(nom[0].split(","));
} else {
add(nom);
}
}
private void add(String[] list) {
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The varargs part can be empty. So you can get what you want with
public Groupe(String nom){
String[] list = nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
public Groupe(String nom1, String nom2, String...nom){
this.nom.add(nom1);
this.nom.add(nom2);
for(String item:nom)
this.nom.add(item.toLowerCase());
}
You could also, of course, use one ctor with an if statement on the length of the input array, splitting out cases 0 (not handled with the code above), 1, and > 1.
public class OverloadVarArgs {
public static void main(String... args){
OverloadVarArgs a = new OverloadVarArgs("One Argument");
OverloadVarArgs b = new OverloadVarArgs("Two", "Arguments");
OverloadVarArgs c = new OverloadVarArgs("One, Argument");
}
public OverloadVarArgs(String a){
System.out.println("Constructor 1");
}
public OverloadVarArgs(String... a){
System.out.println("Constructor 2");
}
}
Output:
Constructor 1
Constructor 2
Constructor 1