If I create an object with a constructor in one class, and the constructor gives the object a property like 'name', is there a way to access specifically the String 'name' from another class? As in, if I have a method that I pass the objects to, and that method needs to access just the String 'name' from the constructor, how do I get to it?
This is probably a bad question that already has an answer, but since I don't know the right terminology to search for it I'm a bit stuck...
You cannot read parameters passed to a constructor from outside the constructor definition, unless that parameter is stored in a field of the class. Of course, if you create an instance of a class like MyClass myObject = new MyClass("Some String");, you can access some string in the scope of the code that created the object.
The ways that a field of a class, say the field fieldName from an instance myObject an a class MyClass can be accessed by another class are:
If the field is public, access by myObject.fieldName
If the field is protected, access it by subclassing MyClass
If MyClass has a getter for the field: myObject.getFieldName()
If the field is private and does not have a getFieldName() method, then it cannot be accessed from outside of the class.
Here are a couple of classes that I think demonstrate what you are wanting to do.
I have a Person class that has a name field and a Friend class that has a method called sayHello and it accesses the name property of Person.
public class Main
{
private static class Friend
{
public void sayHello(Person person)
{
System.out.println("Hello " + person.getName());
}
}
private static class Person
{
private String name;
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
public static void main(String[] args)
{
Person person = new Person("John Smith");
Friend friend = new Friend();
friend.sayHello(person);
}
}
Related
I am having trouble with a method that accepts two classes Pokemon as its parameters because it could be whatever pokemon battling, but if I try to catch the name of the subclass, such as Totodile, the superclass's name attribute is printed
in Pokemon.java:
abstract public class Pokemon {
private String name="POKEMON";
public String getName() {
return name;
}
}
in Totodile.java :
public class Totodile extends Pokemon {
String name = "Totodile";
}
in Geodude.java :
public class Totodile extends Pokemon {
String name = "Geodude";
}
in Battle.java :
public class Battle {
public void initiateBattle(Pokemon pokemon1,Pokemon pokemon2){
System.out.println(pokemon1.getName()+ " is battling against " + pokemon2.getName());
}
}
in App.java:
public class App {
public static void main(String[] args) throws Exception {
Geodude geodude = new Geodude();
Totodile totodile = new Totodile();
Battle battle = new Battle();
battle.initiateBattle(totodile, geodude);
}
}
The output is "POKEMON is battling against POKEMON"
, but how could I get "Totodile is battling against Geodude"
You can't "override" a field. When you write:
class Foo {
String name;
}
you are always declaring a new field. If your superclass also has a field with the same name, okay. Now your Totodile class has 2 fields, both named name, one of which has value POKEMON, the other has value Totodile.
Which one do you get when you write myPokemon.name? Depends on the compile-time type of myPokemon (the variable, not the object it is pointing at!) - and given that it is Pokemon in your code, you get the Pokemon version of the name field.
This notion that you have 2 fields with identical names is called 'shadowing'.
Shadowing is a mistake; do not do it unless you really, really know what you are doing.
The solution is therefore quite simple: Don't define a field named name in the Totodile class. Instead, set the value of the name field (which you inherited, so the Totodile class has that name field already, no need to make a second field with the same name and confuse things):
class Totodile {
{ name = "Totodile"; }
}
This somewhat weird syntax creates an instance initializer, as you need to stuff your code somewhere (you can't just start putting statements straight into a class, you need to brace em up). This is a tad odd, the more usual design is instead something like this:
abstract class Pokemon {
private final String name;
public Pokemon(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Totodile extends Pokemon {
public Totodile() {
super("Totodile");
}
}
This is what most java programmers do:
It forces subclasses of Pokemon to actually set the name properly. That default 'POKEMON' value is weird and no longer needed in the above strategy.
It avoids exotic code constructs to make it work. Constructors and abstract classes tend to be a lot more familiar to your average java coder than instance initializers.
Adds final in the appropriate places.
I am trying the Jacco testing and I am able to test the getStudentId from a class called Student which has:
public String getStudentId() {
return studentId;
}
When I try to test my other class named Product, I get an error - the only difference between the two is in the getX method. The getName method of Product is:
public String getName() {
return this.name;
}
and the error message says:
constructor Product in class Product cannot be applied to given types
The keyword this references the instance of the object you are currently in. Imagine having a class like this:
public class A {
private String property;
public void changeProperty(String property) {
this.property = property
}
}
Outside of the method the variable name property is not ambiguous and references the member variable of class A. But it is ambiguous inside the method changeProperty because there is also the argument named property.
How does Java resolves this conflict? If you just type property you will always reference the object with a smaller scope, so the argument of the method and not the member variable. By using this.property you can reference the member variable again.
If there is no such conflict in your object, like in your example, then you do not need the this statement and this.name is the same as name.
However as prevention of very nasty bugs one could always use this when referencing a member variable, just as good practice. Imagine you would create a method with such a name conflict in the future and forget about the member variable, whoops you easily create a bug that is hard to debug.
Some programmers even go further and do always give member variables other names than arguments, to prevent such name conflicts. For example member variables are often named:
mProperty or
_property
Note that the method this(...) references a constructor of the own object. It can be used in a constructor to pass the task to another constructor like:
public class A {
public A(String fileName) {
this(new File(fileName), true);
}
public A(File file) {
this(file, true);
}
public A(File file, boolean doSomething) {
// Code ...
}
}
Analogously there is also the keyword super which references the parent-class. For example:
public class A {
protected String property;
}
public class B extends A {
private String property;
public void foo() {
// Property of B
System.out.println(property);
// The same
System.out.println(this.property);
// Property of A
System.out.println(super.property);
}
}
This keyword can also be used to reference parent-constructor or other methods of the parent class.
So all in all it is just about resolving such name conflicts.
Now we know that, it is easy to see that the code you posted does not contain the bug.
When you use this.name you are using a attribute defined in your class, the attribute name. However, when you use only name, it could be any variable called so in your code, even the attribute. Example:
public String getName(){
String name = "Mery";
this.name = "Jacob";
return name;
}
This method return the value "Mery". If you put return this.name then you return the value "Jacob".
There's a chance you set studentID to a public variable. Anytime you are using this.whatever to return a variable from a getX function, the this. implies it's a private variable. More likely than not the studentID is public and that's why you got away with no 'this.' in front of it.
I have this class:
public class Function{
private String name;
public Function(){
}
public Function(String name){
this.name = name;
}
}
So what if I have two instances of this class, let's call them ins1 and ins2. So how can I know which constructor did they use?
In this specific case the instance that was created with the constructor Function() will return null for the member name because is not initialized...
the other instance has the field name initialized and using its getter you can check if it is null referenced or not.
I have a linkedlist of Accounts, containing Employees and Managers (inheriting from Account). The problem is I have noticed the last added item seems to be overwritting the rest in the list. Why is it doing this? what I am doing wrong? thanks. I'll put my code below and console output. Sorry in advance if i am being really stupid and missing something obvious!
public class Database {
static List <Account> Accounts = new LinkedList<Account>();
public static void main(String[] args) {
Employee Geoff = new Employee("Geoff", "password1");
Manager Bob = new Manager("Bob", "password2");
Employee John = new Employee("John", "password3");
Accounts.add(Geoff);
Accounts.add(Bob);
Accounts.add(John);
list();
}
public static void list() {
for (Account u : Accounts) {
System.out.println(u);
}
}
Console Output is:
John, John, John
:(
Edit: code has been changed sorry guys!
public abstract class Account {
protected static String name;
protected static String passcode;
public User(String name, String passcode) {
this.name = name;
this.passcode = passcode;
}
}
Both manager and employee inherit from this so for manager:
public Manager(String name, String passcode) {
super(name, passcode);
}
Remove key word `static from declaration of fields and it will work fine.
static variables are associated with the class, not with object. Which means those fields are shared between each instance of this class.
Class variables (static) will only have a single instance that is shared between all instanciations of the class. That means that every time you say "this.name", it is semantically equivalent to saying "User.name", since "this" refers to the instance, not the class.
Change the class variables (static variables) to instance variables (non static variables) and everything will work as you expect.
Here is the documentation that explains class vs instance variables.
http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
This question already has answers here:
Java force fields inheritance
(4 answers)
why java polymorphism not work in my example
(3 answers)
Closed 8 years ago.
I'm new to Java. I've had following classes:
public abstract class Beverage {
String description = "Unknown beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
and:
public class DarkRoast extends Beverage {
String description = "Dark roast";
#Override
public double cost() {
return 0.99;
}
}
When I construct a new DarkRoast object:
Beverage beverage2 = new DarkRoast();
I expect it to have desctiption equal to "Dark roast":
assertEquals("Dark roast", beverage2.getDescription());
But actually it's "Unknown beverage". I know I should implement DarkRoast constructor that sets description, but I don't know why, I don't know how it works internally. Shouldn't the subclass field overwrite superclass field?
Shouldn't the subclass field overwrite superclass field?
No - the subclass field is actually an entirely new field. Since you mean to assign to the superclass field, you need to create a constructor like this:
public DarkRoast()
{
description = "Dark roast";
}
(This is unlike the method cost() - technically when you override a non-abstract method you still 'sort of' have the old method as well)
If the subclass must always provide a description, then you could make getDescription abstract, which would force the subclasses to implement and return a value. Just another technique.
Because the called getDescription method is the method of the class Beverage (DarkRoast doesn't have its own), so the method getDescription access to his description property, whose value is "Unknown beverage".
It is allowed for class to hide the members. When you declare a member for field in class and declare in the child class some with the same name you will hide it but not override.
If you want to provide unique name for each class that implement your abstract class you should declare an abstract method
public abstract String getDescription();
Or you can pass the value to the member.
BaseClass(String description) {
this.description = description;
}
then in child class you can use the super to access the constructor
ChildClass(String description) {
super(description);
}
The key word super allows you to access directly the members of parent class.
So in case of your class you could be able to do something like this
private void test() {
System.out.println(super.description); //This will refer to parent class
System.out.println(this.description); //This will refer to child class
}
So when you declare a field you create always a new reference point.
You do not override the .getDescription() method in subclasses; as a result, the method called is the one in Beverage, and the method in Beverage only knows about the description declared (and initialized, in this case) in Beverage itself.
You could have it display the value in all subclasses by using instead:
return this.description;
However, there is a much better way to solve this problem; and that is:
public abstract class Beverage
{
private final String description;
public abstract Beverage(final String description)
{
this.description = description;
}
public final String getDescription()
{
return description;
}
// etc
}
// Subclass
public class DarkRoast
extends Beverage
{
public DarkRoast()
{
super("Dark Roast");
}
}
You should note that it makes no sense at all to describe an "Unknown beverage" to start with. Beverage being abstract, it cannot be instantiated! The solution proposed here basically forbids anyone from creating a Beverage without a description, so it's a win-win ultimately.
The problem is there are 2 attributes called description, one in the super class 'Beverage' and one in the subclass 'DarkRoast', and since you are using Beverage as the the reference type you get the description attribute/instance variable of the reference class and that of the subclass is shadowed(not accessible at least to my humble knowledge in Java).
You don't need to define the attribute again in the subclass because it's already there, so basically if you remove the attribute description from the DarkRoast class you will find that it will print unknown description as well, because it is already there.
To make things more clear try this code to see how there are 2 different description instance variables.
public class DarkRoast extends Beverage {
String description = "Dark roast";
public String getDescription() {
return description;
}
public String getSuperDescription() {
return super.description;
}
#Override
public double cost() {
return 0.99;
}
public static void main(String[] args) {
DarkRoast b = new DarkRoast();
System.out.println(b.getDescription());
System.out.println(b.getSuperDescription());
}
}
To see the shadowing try to do the following:
public static void main(String[] args) {
Beverage b = new DarkRoast();
DarkRoast b2 = new DarkRoast();
System.out.println(b.description);
System.out.println(b2.description);
}