java generic wildcard not working as expected - java

The code shown below was given to explain generic wildcard usage.
I have a Student parent class and Dayscholar child class. I have Record<Student> class that maintains a list of Student/Dayscholar objects and a method named display that accepts a parameter of Record<? extends Student> and displays the list. This works with either Record<Student> or Record<Dayscholar>. And according to what I understood from the course the wildcard is required. Meaning if declaration of display method is changed to display(Record<Student>) the method will not accept the parameter Record<Dayscholar> and will issue a compile time error.
But declaring display method as display(Record<Student> somename) worked just as fine with record of type Student or of type Dayscholar. I am confused. What would be best example to demonstrate generic wildcard?
class Record<Student>//<Number>
{
List<Student> record =new ArrayList<>();
#Override
public String toString() {
return "Record [record=" + record + "]";
}
public void add(Student e)
{
record.add(e);
}
public void display(Record< Student> record) {
System.out.println("student record:"+record);
}
}
class Student
{
int id;
String name;
public Student(int id,String name)
{
this.id=id;
this.name=name;
}
#Override
public String toString()
{
return "Id = "+id+" Name = "+name;
}
}
class Dayscholar extends Student
{
float stipend;
public Dayscholar(int id,String name,float stipend)
{
super(id,name);
this.stipend=stipend;
}
#Override
public String toString()
{
return "Id = "+id+" Name = "+name+" Stipend = "+stipend;
}
}
class WildcardsDemo
{
public static void main(String[] args)
{
Record<Student> studentrecord = new Record<>();
studentrecord.add(new Student(9999,"hassan"));
studentrecord.display(studentrecord);
Record<Dayscholar> dayscholar = new Record<>();
dayscholar.add(new Dayscholar(2222,"Sam",900));
dayscholar.display(dayscholar);
}
}

Everything in my post was correct until few hours ago (now it is 11pm US ET) when I ran the code/s again. I ran the code in play ground of training course and wild card proved to be holding to my surprise. I don't know how explain this. Is it my laptop / is it that the browser was caching previous good runs? I hope this will not be considered as a point against me.

Related

How to call a method from a class which implements an interface, through the interface?

I have the following interface:
public interface IStaff {
public StaffPosition getPosition();
public String toString();
}
and the class:
public class Worker implements IStaff {
private String name = null;
private String surname = null;
private int age = 0;
//StaffPosition is an enumeration class
private StaffPosition position= null;
public Worker (String name, String surname, int age, StaffPosition position){
this.name = name;
this.surname= surname;
this.age= age;
this.position= position;
}
#Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(this.name);
buffer.append(" ");
buffer.append(this.surname);
return buffer.toString();
}
#Override
public StaffPosition getPosition() {
return this.position;
}
public int getAge(){
return this.age;
}
In another class - Building, I have a HashMap<Office, IStaff> officeswhere Office is a normal class which only holds the number of the office and has a getter for that number.
And then in a yet another class Company I have an ArrayList<Building> buildings, which holds information about all the buildings of a company. In this class I need to get the age of a worker but how can I do that? So far I have a loop like this to get to the map:
for (Building building: buildings) {
for (Map.Entry<Office, IStaff> office: building.offices.entrySet()) {
//get the age of a worker
}
}
Is there a way to do that?
The only real answer is: when you need such an information in places where only your interface should show up, then that information needs to sit on the interface.
So your interface could have a method getAge(), or maybe getBirthday().
Side notes:
using I for "interface" in class names ... is bad practice, or at least: very much against java conventions.
you don't need to have a toString() in your interface. You get one from Object anyway.
(of course, there are dirty tricks, like doing an instanceof check somewhere, and then casting to the type of the concrete class. But as said: that is really bad practice)
Make IStaff an abstract class and then call the method.

Passing an object array to method

So I want to use a method to write multiple objects to respective files. However I do not know how to import the array of Objects without defining the specific Object.
The people is class is purely for storing the created objects in arrays so it is easier to access across other classes.
For example
public class People {
private Student[10];
private Teacher[10];
public void setStudentArray(Student, index) {
Student[index] = Student;
}
public void setTeacherArray(Teacher, index) {
Teacher[index] = Teacher;
}
}
public class Student extends People {
String name;
int StudentID;
public String getName() {
return name;
}
}
public class Teacher extends People {
String name ;
int Teacher ID;
public String getName() {
return name;
}
}
public class Main {
People p = new People();
public void main (String[] args) {
Student s = new Student("default-name" , 1);
p.setStudentArray(s, 0);
Teacher t = new Teacher("default-name", 1);
p.setTeacherArray(t, 0);
outputName(p.getStudentArray, 0);
outputName(p.getTeacherArray, 0)
}
//THIS IS WHERE I AM STRUGGLING I dont know how to pass teachers or students array to it.
//I want the Object[] parameter to accept both Student[] and Teacher[]
public void outputName(Object[], index) {
System.out.println(Object[index].getName);
}
}
I think that my Method taking an Object[] is wrong but I do not know how to approach it otherwise. I believe the issue is that Object[] is an entirely different class to Teacher[] and Student[] and this is where I am going wrong.
I want to use the .getName method in both the classes of Teacher and Student in order to print the name of the Teacher of Student. (Merely so I can see the passing is working.)
If this is just not possible I guess I will just not try a method that can take different objects.
I know that I can just use two methods one for students and one for teachers but I want the method to work for multiple objects so that I can add more object arrays to it.
So People class is extended by both Student and Teacher.
What commonalities are here?
String name is present in both Student and Teacher
public String getName() is also present in both Student and Teacher
You can move these commonalities to People class. Also ensure to remove the name attribute and getName from Student and Teacher class
So your People updated class can be:
public class People {
private String name; //Newly added
private Student[10]; //This ideally shouldn't be in People class rather a different class
private Teacher[10]; //This ideally shouldn't be in People class rather a different class
public void setStudentArray(Student, index) {
Student[index] = Student;
}
public void setTeacherArray(Teacher, index) {
Teacher[index] = Teacher;
}
public String getName() {
return name;
}
public void setName() {
this.name = name;
}
}
The outputname method should be like:
public void outputName(People[] people, index) {
System.out.println(people[index].getName());
}
NOTE: I am not correcting the syntax here, but just giving an idea.
What #Li357 said is right... You have to change your modeling a bit. Even if you managed to pass Student[] as an Object[], you wouldn’t be able to call the getName method as it’s not an Object method.
So a better modeling would be to make the getName method a People method, and both Student and Teacher classes would inherit it.
Then you could receive People[] as the outputName method argument, and use the getName method inside.
First of all learn how to declare array and choose valid variables.
In your People class do following modifications.
public class People {
//Declare arrays like this.
private Student[] student;
private Teacher[] teacher;
//Initialize arrays
public People(){
student = new Student[10];
teacher = new Teacher[10];
}
public void setStudentArray(Student s,int index) {
student[index] = s;
}
public void setTeacherArray(Teacher t, int index) {
teacher[index] = t;
}
//Add getter methods
public Student[] getStudentArray(){
return student;
}
public Teacher[] getTeacherArray(){
return teacher;
}
}
Inside sub classes Student and Teacher add Argument constructor
Finally in your outputName method you can do something like this.
public static void outputName(Object[] obj, int index) {
if(obj instanceof Student[]){
Student[] s = (Student[])obj;//parsing to student array
System.out.println("Student name : "+s[index].getName());
}
if(obj instanceof Teacher[]){
Teacher[] teacher = (Teacher[])obj;//parsing to teacher array
System.out.println("Teacher name : "+teacher[index].getName());
}
}
Output:
Student name : default-name
Teacher name : default-name

Creating an incremental number sequence in Java

So I'm creating a student database thing for a school project. My first issue is that upon creating a new student I should see "Application number ### has registered successfully". Now the problem is that we have to have that number generate (### referring to the number) sequentially from 1 every time a new application is recorded. How would I go about doing that?
So far this is what there is but I can't seem to get the number to generate incrementally.
public TestApplication(String Surname, String personalIdNo)
{
if (isValidpersonalIdNo(personalIdNo) == true)
{
Student.add(Surname);
Application.put(personalIdNo, Student);
System.out.println("Application number ### " + "has registered successfully");
}
else
{
System.out.println("Application has failed, Personal id: " + personalIdNo);
}
}
Any help with this would be appreicated.
Since you seem to be using lots of static methods, I believe the best thing for you to do in this case is to create a static field called latestId and a static method called generateId, both in the Student class. Then you can call the generateId method whenever you call Student.add.
However, please note that this solution does not work if your application is multithread.
public class Student {
private static int latestId = 0;
public static int generateId() {
return ++latestId;
}
...
}
You can write a singleton class that will produce the ids for you:
class Generator {
private AtomicInteger count = new AtomicInteger(1);
private static Generator generator = new Generator();
private Generator() { }
public static Generator getInstance() {
return generator;
}
public int generate() {
return count.getAndIncrement();
}
}
Now, when you need to get a new id, you just call the generate method. The AtomicInteger is used because you might need the id from multiple threads and it will make the concurrent access safe.
The singleton Generator provides a single entry point to the id-generating facility.
You can use your storage type to give you the amount of added students that were put into DB.
I don't know what type you use to store your students. If it is hashmap or vector you can use size method to print students count. So I assume if you have Application.put you probably have a field in your Application type that is used to store each student. Then you can add a method like getStudentsCount to it and you should be all set. Since I don't know much about your Application type the above is all assumptions. Below you can find how I would solve that:
import java.util.HashMap;
import java.util.Vector;
class Student{
private String name;
private int personalID;
public Student(String name, int personalID){
this.name = name;
this.personalID = personalID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPersonalID() {
return personalID;
}
public void setPersonalID(int personalID) {
this.personalID = personalID;
}
}
class DB{
private HashMap<Integer, Student> students = new HashMap<Integer, Student>();
public boolean addStudent(Student student) {
Integer studentId = new Integer(student.getPersonalID());
if( !students.containsKey(studentId)){
students.put(new Integer(studentId), student);
return true;
}
else
return false;
}
public int getStudentCount() {
return students.size();
}
}
class Operations{
DB db;
public Operations(DB db){
this.db = db;
}
public boolean addStudent(String name, int personalID){
Student student = new Student(name, personalID);
return db.addStudent( student );
}
}
public class SimpleStudentDB {
public static void main(String [] args){
DB db = new DB();
Operations operations = new Operations(db);
if( operations.addStudent( "Jason", db.getStudentCount()+1) )
System.out.println("Student added successfully. DB contains ###"+db.getStudentCount()+" elements");
else
System.out.println("Operation failed");
}
}

Access attribute of a subclass [duplicate]

This question already has answers here:
Check attribute of a subclass
(3 answers)
Closed 9 years ago.
I stumbled across that situation but I don't know how to handle it the right way:
class Coffee { }
class CoffeeMix extends Coffee {
public boolean shaken;
}
I'm saving the coffee items in an array list:
ArrayList<Coffee> coffees = new ArrayList<Coffee>();
So in this array list exist normal coffee objects and coffee mix objects. Now I want to display all coffee mix objects, that are shaken:
for(Coffee c : coffees) {
//here is the same problem as above
}
As I read in some answers on stackoverflow: instanceof seems to be a bad idea, because it screws the idea behind oo up. So how to handle this?
First of all, when we talk about OO we shouldn't use public fields.
I understand why you want to avoid to use instance of.
In this case you can use polymorphism and dynamic binding. You can add abstract isShaken method to the base class, make shaken as private at CoffeeMix and override isShaken (return shaken)
You should indeed use polymorphism. That is the best way to go here. But you want you can also use getclass en check if it equals the class that referring to.
You could use the Visitor pattern.
Here's an example how it could be applied to your case:
interface CoffeeElement {
void accept(CoffeeVisitor visitor);
}
interface CoffeeVisitor {
void visit(Coffee coffee);
void visit(CoffeeMix coffee);
}
class Coffee implements CoffeeElement {
private final String name;
public Coffee(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public void accept(CoffeeVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return "Coffee [name=" + getName() + "]";
}
}
class CoffeeMix extends Coffee {
public CoffeeMix(String name) {
super(name);
}
#Override
public void accept(CoffeeVisitor visitor) {
visitor.visit(this);
}
#Override
public String toString() {
return "CoffeeMix [name=" + getName() + "]";
}
}
class PrintingCoffeeVisitor implements CoffeeVisitor {
#Override
public void visit(Coffee coffee) {
// ignore regular coffee
}
#Override
public void visit(CoffeeMix mix) {
System.out.println(mix);
}
}
class CoffeeTest {
public static void main(String[] args) {
List<Coffee> coffee = new ArrayList<Coffee>();
coffee.add(new Coffee("Java"));
coffee.add(new Coffee("Molokai"));
coffee.add(new CoffeeMix("Season Blend"));
CoffeeVisitor v = new PrintingCoffeeVisitor();
for (Coffee c : coffee) {
c.accept(v);
}
}
}
You can also read this explanation of the Visitor pattern. I found it very useful.
https://stackoverflow.com/a/2604798/467874
instanceof seems appropriate here, but if you really don't want to use it, you could try something ugly:
for (Coffee c : coffees) {
try {
CoffeeMix blend = (CoffeeMix) c;
//whatever you want to do with CoffeeMix objects
} catch (ClassCastException cce) {
//whatever you want to do with Coffee objects
}
}
This seems like a situation in which the cure is worse than the disease, but so long as CoffeeMix objects have some fields or properties which are unavailable to Coffee objects, the exception should be thrown, and you will have accomplished your class-wise sorting without having used instanceof at great cost to proper technique.

what is the error in this code and why?

class Person {
String name = “No name";
public Person(String nm) { name = nm; }
}
class Employee extends Person {
String emplD = “0000”;
public Employee(String id) { empID = id; }
}
public class EmployeeTest {
public static void main(String[ ] args)
{
Employee e = new Employee(”4321”);
System.out.println(e.empID);
}
}
The constructor of Employee must call its super constructor, the constructor of Person.
public class Person
{
private String name;
public Person(String nm)
{
this.name = nm;
}
public String getName()
{
return this.name;
}
}
public class Employee extends Person
{
private String emplD;
public Employee(String nm, String id)
{
super(nm);
this.empID = id;
}
public String getId()
{
return this.empID;
}
}
public class EmployeeTest
{
public static void main(String[] args)
{
Employee e = new Employee("Some Name", "4321");
System.out.println(e.getID());
}
}
Change “No name’ into “No name" (closing quotes)
Maybe it's here:
String name = “No name’;
should it be:
String name = "No name";
Also, I'm not sure if this is the editor that you've pasted it in from doing this, but this is wrong too:
Employee e = new Employee(”4321”);
should be:
Employee e = new Employee("4321");
A number of things:
You're using the wrong kind of quote characters around your strings. You need to use ". Not “, ', or ”.
Your Person class has no default constructor. Because of this you must explicitly call super("some name"); as the first line of your Employee constructor (I would suggest adding a constructor that takes both name and employeeId as parameters).
You declared the property as emplD (with a lower-case L character), but you try to assign to it as empID (with an uppercase I character). You can call it whatever you want, but the name needs to match in both places.
Your object design violates the basic principles of encapsulation. The name and empID properties should be private fields, and if external classes need access to these values, then you should provide the appropriate public getter methods. In other words, instead of e.empID you should be able to say e.getEmpID().
It is generally not good coding style to define multiple classes in a single file, particularly when all of them are meant to be publicly accessible.
Change this line
String name = “No name’;
to:
String name = “No name";
check your closing qoutes.
Your empID field is not public / there is no accessor method for it / it is not defined as a property. Also don't expect people to help if you provide absolutely no information on the error other than the source code and a vague post title.
You have to call the constructor of the superclass (Person) in the constructor of the class `Employeesuper(id); Please find the correct code below.
public Employee(String id) {super(id);empID =id;
Calling a super class constructor would fix the issue !
public class Person {
String name = "No name";
public Person(String nm) { name = nm; }
}
public class Employee extends Person {
String empID = "0000";
public Employee(String id) {
super("Some Name");
empID = id; }
}
public class EmployeeTest {
public static void main(String[] args){
Employee e = new Employee("4321");
System.out.println(e.empID);
}
}

Categories

Resources