I'm trying to pass value to constructor and print the values.
open class Car(c: Int){
open var cost: Int = c
init {
println("This comes First $cost")
}
}
open class Vehicle(cc: Int) : Car(cc) {
override var cost: Int = 20000
init {
println("This comes Second $cost")
}
fun show(){
println("cost = $cost")
}
}
fun main() {
var vehicle = Vehicle(1000)
vehicle.show()
}
Output
This comes First 0
This comes Second 20000
cost = 20000
if i just comment this line
override var cost: Int = 20000
output would be
This comes First 1000
This comes Second 1000
cost = 1000
Why super constructor cost is zero when override the property in subclass?
I need this to be compared to java concept for better explanation here
In Java to create a mutable property cost, you need to define a field cost and a getter and setter:
public class Car {
private int cost;
public Car(int c) {
this.cost = c;
System.out.println("This comes First " + getCost());
}
public int getCost() { return cost; }
public void setCost(int cost) { this.cost = cost; }
}
Kotlin has the concept of a property embedded in the language, so you can achieve the same with only creating a var property as you did:
open class Car(c : Int){
open var cost : Int = c
init {
println("This comes First $cost")
}
}
This is much more concise from the developer perspective, but the implementation is the same. Kotlin compiler is generating a field cost, a get method and set method for us under the hood.
Now the interesting part. When you make the cost property in the parent class open and overrides it in the child class, you are actually overriding the get method. It is not possible to override a field, neither in Kotlin nor Java.
As #Pawel mentioned in his answer that's the java code for the Vehicle child class:
public class Vehicle extends Car {
private int cost = 20000;
#Override
public int getCost() {
return this.cost;
}
#Override
public void setCost(int var1) {
this.cost = var1;
}
public final void show() {
System.out.println("cost = " + getCost());
}
public Vehicle(int cc) {
super(cc);
System.out.println("This comes Second " + getCost());
}
}
When you execute println("This comes First $cost") in the parent class, you are actually executing System.out.println("This comes First " + getCost()); and the actual getCost() being called is the one in the child class Vehicle. As the child class cost field has not been initialized yet, as we are still executing the super(cc) call, its value is zero.
Have you looked at generated bytecode and tried to reverse decompile it back to java? If you're confused how Kotlin works under the hood often times it can help you understand.
In this case your classes in Java would look like this (i decompiled your code and cleaned it up a little):
public class Car {
private int cost;
public int getCost() {
return this.cost;
}
public void setCost(int var1) {
this.cost = var1;
}
public Car(int c) {
this.cost = c;
System.out.println("This comes First " + getCost());
}
}
public class Vehicle extends Car {
private int cost = 20000;
public int getCost() {
return this.cost;
}
public void setCost(int var1) {
this.cost = var1;
}
public final void show() {
System.out.println("cost = " + getCost());
}
public Vehicle(int cc) {
super(cc);
System.out.println("This comes Second " + getCost());
}
}
What's happening is open var is just declaration for setter and getter which Vehicle overrides.
Remember that initialization of super class always happen before child, so when Car constructor is executed Vehicle is still not initialized (Vehicle.cost is still 0).
That means in first case:
This comes First 0 // Car constructor prints 0 because it returns Vehicle.cost which is unitialized
This comes Second 20000 // Vehicle constructor returns initialized value
cost = 20000
And in second case where you DON'T override the cost, both Car and Vehicle return Car.cost:
This comes First 1000 // Car constructor assigns constructor parameter to Car.cost and returns it
This comes Second 1000 // Vehicle constructor returns Car.cost as well
cost = 1000
Also note that in first case your constructor parameter is meaningless: it gets assigned to Car.cost but that field is inaccessible because it's shadowed by Vehicle.cost.
This behavior may not be intuitive, but it's the result of how properties work with the JVM.
When you subclass Car, the Car initialization occurs before the subclass Vehicle initialization. So the println call in Car's init block accesses the property before Vehicle is initialized. Since this access amounts to calling a getter method in Java, it is accessing the subclass's getter, not its own since it's been overridden. Since the subclass has not initialized yet at this stage, its getter returns the default value of the backing field, 0.
If you do this with a non-primitive, non-nullable property, you can "trick" Kotlin into giving you a Java NullPointerException for what can normally be assumed to be non-null.
In either case, the default code inspections should warn you about trying to access an open property during initialization, because of this unexpected kind of behavior.
The work-around would be to use a private backing property:
open class Car(c : Int){
private var _cost: Int = c
open var cost : Int
get() = _cost
set(value) { _cost = value }
init {
println("This comes First $_cost")
}
}
In simple words.
when object is created Vehicle(1000)
- first init will get called
- then variables get initialized
step 1:- it will try to call constructor of Vehicle
step 2:- since it inherited Car it will try to call constructor of Car first
step 3:- it always look for override methods not overridden methods or properties So, $cost is pointing to override property.
step 4:- override var cost : Int = 20000 is not initialized when you are printing
println("This comes First $cost") as init run first then property will initialized.
step 5:- So $cost is by default zero.
Just try this, below open var cost : Int = c
put, var costTest : Int = c. "no open keyword"
Then, on Vehicle init put,
println("This comes Second $cost $costTest")
here you will get costTest = 1000.
Its because costTest you haven't override
Related
The purpose of this program is to create a class and tester class for a select object(in my case a monitor), with at least one overloaded method. And in the client class, I have to instantiate at least three instances of the object. So far I believe I've finished the first class with the declaration of methods, getters and setters, and constructors. The problem occurs in my tester class, where I get the error "Cannot resolve method 'MonitorV82' in 'Monitor V82'. I don't know for sure why I'm getting this error, any advice?
My first class is:
public class MonitorV82
{
private double l;
private double h;
//one parameter constructor, all private instance variables initialized
public MonitorV82(double monitor1Height) {
//2.When this gets name1(jupiter), it designates "jupiter" to the variable "n"
h = monitor1Height;
l = (monitor1Height * 1.77);
}
//two parameter constructor
public MonitorV82(double monitor1Height, double monitor1Length){
//3.When this gets name1(jupiter), and a double, it sets jupiter to "n" and the diameter to "d"
h = monitor1Height;
l = monitor1Length;
}
public double getMon1height() { return h; }
public double getMon1Length() {
return l;
}
public void setMon1height(double name) { h = name; }
public void setMon1Length(double diam) {
l = diam;
}
public String monType(int resolution)
{
String monitType = "";
if (resolution == 1080) {
monitType = "lenovo";
} else if (resolution == 4000) {
monitType = "samsung";
}
return monitType;
}
//overloaded method
public String monType(int pixLength,int pixHeight)
{
String monitType = "";
if (pixHeight == 1080) {
monitType = "lenovo";
} else if (pixHeight == 4000) {
monitType = "samsung";
}
return monitType;
}
}
My tester class(where the error is) is:
public class V8Tester {
public static void main(String[] args) {
double length1 = 32.2;
double height1 = 51.8;
double length2 = 31.8;
double height2 = 50.6;
int resolution = 0;
MonitorV82 monit1 = new MonitorV82(length1);
resolution = monit1.MonitorV82(height1);
}
}
I am still learning Java in school so please don't roast me if something seems obvious or simple. Thank you for your help.
You are getting this error because there is no method MonitorV82, only a constructor. Also you are trying to instantiate the int variable resolution with a MonitorV82 object, which is not possible, because the compiler expects an int value.
If you want the resolution that refers to the pixel count of the MonitorV82 object with known pixel height, you first need to find out it's pixel length. You can do this by using your getMon1length() method and the calculate the resolution by length * height. Ultimately what I think you are trying to do is:
int heightMonit1 = monit1.getMon1height();
int resolution = (int)length1 * (int)heightMonit1;
You need to type cast, because you want to instantiate the int variable resolution with a calculation of double values.
You could however also use your second constructor and do:
MonitorV82 monit1 = new MonitorV82(length1, height1);
int resolution = (int)monit1.getMon1height() * (int)monit1.getMon1length();
Before answering the question in the title, you need the answer to this question:
What is a constructor in Java?
A constructor in Java is a special method used to "construct" (build, instantiate, etc.) objects. A constructor follows these basic rules:
The name of the constructor should match exactly the class name. In your case, MonitorV82 is this name.
A constructor doesn't have a return type. The new operator is responsible for returning a new object matching the type of the class in which the constructor is being invoked.
Knowing this, let's address the original question: Why the error? Because in MonitorV82 there is only a constructor a with matching name, but not a regular method with the same name. Consider my example below
public class Test {
private String name = "default";
// constructor #1
public Test() {}
// constructor #2
public Test(String name) {
this.name = name;
}
// method #1
public void Test() {
System.out.println(name);
}
// method #2
public void Test(String name) {
System.out.println(name);
}
}
Notice that in the code above, I have two constructors and two methods with the same name (matching case) and same parameters. This is allowed in Java although this is STRONGLY discouraged due to how confusing it can get.
What does this mean for you?
To create monit1, you need to invoke a CONSTRUCTOR. Once you construct the object, you cannot use it to invoke a constructor. You use objects to invoke non-static, accessible methods. Based on this, the line
MonitorV82 monit1 = new MonitorV82(length1);
is totally fine. However, the set resolution line is not resolution = monit1.MonitorV82(height1); because you have no METHOD named MonitorV82 (you just have a constructor with a matching name). You fix this by creating a method in your class that does exactly that. Since method names should be descriptive of their function, creating a method named setResolution or calculateResolution should be fine. What you should not do is used an ambiguous name; especially using the same name as the constructor.
Lastly, I will leave you with this small piece of advice: Just because the language allows you to do something, that does not mean that it is correct or OK to do so. My code example (along with this lengthy explanation) should've illustrated this point.
tl;dr
You asked:
Why am I getting the error "cannot resolve method "x" in "x""?
Because your last line tries to call a method named MethodV82 which does not exist on an instance of the class named MethodV82.
Details
Firstly, you should have indicated which line of code is causing that error.
You have at least one offending line, that last line. The code monit1.MonitorV82(height1) makes no sense. That code is trying to call a method named MonitorV82 on the instance named monit1. But of course there is no such method. Thus the error « Cannot resolve method ».
I cannot follow your logic, so I cannot give a fixed replacement code snippet.
I think you are misunderstanding the use of constructors.
I guess that what you want to do with your monit1.MonitorV82(height1) is to set the height of your monit1 instance to height1.
You need to call the setter to do so, not a constructor. The constructor is not known as a class method, that is why your error occurs. Use
monit1.setMon1height(height1);
Next, I think that you are trying to retrieve a resolution from your monitor, but you have no method inside of your MonitorV82 with this aim so I suggest that you create a method for this such as
public int computeResolution() {
return this.h * this.l;
}
In your test class you end up with:
public class V8Tester {
public static void main(String[] args) {
double length1 = 32.2;
double height1 = 51.8;
double length2 = 31.8;
double height2 = 50.6;
int resolution = 0;
MonitorV82 monit1 = new MonitorV82(length1);
monit1.setMon1height(height1);
resolution = monit1.computeResolution();
}
}
Edit: Even the instantiation of your monit1 does not seem correct. The only one parameter constructor you have is based on height and you are calling it with length1
Edit2: My example of computeResolution() will probably end up with an exception as I am returning an int from a compute action on doubles. But I think that it is not the main issue here
The code from my class, I don't understand it totally. I read on internet that compareTo() method is used for comparing strings to strings and objects to strings,but in my code it is used to compare float to strings, I guess?! Can you explain how is used comparedTo() method in the code below and why do we use it in our case?
package ro.ase.acs.classes;
import ro.ase.acs.interfaces.Mobility;
//Comparable is a generic interface; click add unimplemented methods ; the method will appear at the end of the class
public final class Car extends Vehicle implements Mobility, Cloneable,Comparable<Car> {
public static final int maxNbOfKm = 1_000_000;//it is static, in order to acces it use .
private EngineType engineType;
private float speed;
public Car() {
super();
engineType = EngineType.gas;
speed = 0;
}
public Car(String _name, EngineType _engineType, float _speed) {
super(_name, true);
engineType = _engineType;
speed = _speed;
}
#Override
public void Start() {
System.out.println("The " + engineType.toString() +
" car has started!");
}
#Override
public void Stop() {
System.out.println("The " + engineType.toString() +
" car has stopped!");
}
#Override
public void DisplaySpeed() {
System.out.println(String.format("The %s car runs with %f km/h",
engineType.toString(), speed));
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("The car named ");
sb.append(name);
sb.append(" has a(n) ");
sb.append(engineType.toString());
sb.append(" engine and is running with ");
sb.append(speed);
sb.append(" km/h");
return sb.toString();
}
#Override
public Object clone() throws CloneNotSupportedException {
Car c = (Car)super.clone();
c.engineType = engineType;
c.speed = speed;
return c;
}
#Override
public boolean equals(Object obj) {
if(!(obj instanceof Car)) {
return false;
}
else {
Car c = (Car)obj;
return name.equals(c.name);
}
}
#Override
public int hashCode()
{
return 31*name.hashCode()+13*(HasEngine()?1:0)+7*engineType.hashCode()+(int)speed*100;
}
public enum EngineType { gas, diesel, electric, hybrid }
#Override
public int compareTo(Car o) {
if(speed==o.speed)
{return 0;}
else if (speed>o.speed)
{
return 1;
}
else
{return -1;}
}
// public final int hashCode() {
// return engineType.hashCode();
// };
}
The contract of the Comparable interface, respectively the compareTo() method is:
it returns 0 when both objects are considered "the same" from an ordering perspective
it returns -1 respectively +1 (to be precise any negative or positive value) to indicate when the "other" object is less respectively greater than "this" object.
In other words: the method provides a mean to define a natural order of objects that can be ordered.
If ordering cars by their speed actually makes sense is a completely different story. I would argue that: no, that doesn't make sense. If at all, you could/should define external Comparator objects that define different ways of "ordering" cars, and then a SpeedComparator would obviously order by speed (but in an explicit way).
It doesn't matter what you compare, you can resolve which comes first and which second by what you define. In compareTo methods, -1 means that it comes first and the element you compare it to, comes after that. 1 means that it comes after the element and 0 means they are equal and doesn't get rearranged.
If speed is bigger then it comes later in your list, if it's smaller it comes after. Strings are compared by length for example, if you do "Chicken".compareTo("Cow") then chicken comes after.
compareTo() method is used to sort object of a specific class.
In your case it compares Car objects by value of their speed property.
So you can use it to sort list (or array) of Car objects by values of their speed property.
I have a java program that models a tv and has stuff like power, channel, volume etc. It also has a unique Serial number that is automatically set (increments 1)
However, for my last array item array[2] I need to referernce my array[0] doing this works but my serialNo is no longer unique and just increments 1 (acts like a new tv has been created)
I think your problem lies in the usage of
public static int serialNo() {
return serialNo++;
}
Each time you call this method, you increment the content of the static field.
There is no direct relation between a TV and its serial number.
I suggest that you create a private field serialNumber in the TV class and assign e.g. in the constructor serialNo to serialNumber and then increment.
serialNo is static member of Tv class, this is what Oracle's documentation says about statics.
Fields that have the static modifier in their declaration are called
static fields or class variables. They are associated with the class,
rather than with any object. Every instance of the class shares a
class variable, which is in one fixed location in memory. Any object
can change the value of a class variable, but class variables can also
be manipulated without creating an instance of the class.
In this case, serialNo is not really associated with any object. So, there won't be something like serialNo of the reference at array[2] in this code.
Now, coming back to the question, you have a for loop that increments serial number as shown below:
for (int i = 0; i < tvDetails.length; i++) {
System.out.println(SERIAL_NO + "\t\t" + tvDetails[0].serialNo() + "\n");
It executes tvDetails.length times (3) ad hence, the number gets incremented. If you don't want it to be incremened there then you need to make a couple of changes:
Remove return serialNo++; from serialNo() method and just return serialNo:
public static int serialNo() {
return serialNo;
}
Increment serialNo in Tv's constructor, e.g.:
public Tv(boolean tvPower, int channel, int volumeLevel) {
this.tvPower = tvPower;
this.channel = channel;
this.volumeLevel = volumeLevel;
serialNo++;
}
The problem is here:
public static int serialNo() {
return serialNo++;
}
This violates the SRP, the Single Responsibility Principle, by doing four things:
* Initializes an instance's serialNo,
* Generates a global "next serial no",
* Reports the global serial no, and
* Reports the instance's serial no, impossible for a static member.
Don't use the same name for different things.
public class Tv {
private static int universalSerial; // not thread-safe
public static int getUniversalSerial() {
return universalSerial;
}
static int dispenseUniversalSerial() {
return universalSerial++;
}
private final int serial;
public Tv () {
this.serial = dispenseUniversalSerial();
}
public int getSerial() {
return serial;
}
#Override public boolean equals(Object other) {
if (this == other) { return true; }
if (! (other instanceof Tv)) { return false; }
Tv otherTv = (Tv) other;
return serial == otherTv.serial;
}
#Override public int hashCode() {
return serial;
}
#Override public String toString() {
return "Tv " + serial;
}
}
Notice how the four tasks are split up between static and instance behaviors. Notice how the different names label different things. Notice the elimination of name parts like No that indicate implementation. Notice the coordinated overrides of the Big Three methods, equals, hashCode, and toString. Notice the lack of override for the fourth member of the Big Three, compareTo. That's deliberate. Notice the lack of thread safety. Notice that the instance serial field is final.
All of those decisions have purpose, and are boilerplate for value classes. The example implementation here is bog standard for non-thread-safe, non-comparable value classes with a factory. You should be able to code one of these up in about 10 minutes. It's a great kata to practice it.
I am trying to build a complete program from the partial code of a book. The difficulty is when a variable's modifier is set to private, I can't access it from the main method of my BankTest class after instantiating an object. Am confused on how to pass the Dollar Object as I can't set it to a primitive type like double or float.
Is there a way to set the Dollar object with amount = 100, so that when I run the BankTest class, I could get it to print the getAmount = 100 ? I want to maintain the Dollar object as the parameter of a method if possible ?
final class BankTest {
public static void main(String args[]) {
BankAccount ba = new BankAccount();
Dollar d = new Dollar(100);
//d.setAmount(100.00); "IF class Dollar method is PUBLIC"
//ba.deposit(d); "How to set the value of Dollar Object ??
System.out.println("Balance available: " + d.getAmount());
}
}
final class BankAccount {
private Dollar balance;
private boolean receipt;
public void deposit(Dollar amount, boolean receipt) {
balance.add(amount);
// if receipt == true, print receipt
}
public void deposit(Dollar amount) {
// validate and chain to base method
deposit(amount, true);
}
}
final class Dollar {
private double amount = 0;
public Dollar(double _amount) {
setAmount(_amount);
}
private void setAmount(double amt) { //can only be called by within Dollar class
// make sure amt is a valid currency amount
amount= amt;
}
double getAmount() {
return amount;
}
public void add(Dollar amt) {
// validate amt
amount+= amt.getAmount();
}
}
It seems Dollar was created to not be modified, but I wonder why the attribute is not final and why it can be modified by adding another Dollar object...
The idea is you have to create a new instance of Dollar every time you need a new value. Something similar happens with String and any primitive wrapper class (Integer, Float...).
As you are taking the code from a book you can decide how to deal with it: you can make the setter public or you can live with the current status and create a new object when needed.
You can already add an amount, so I think I'd modify the setter to public
Simply make setAmount public.
And also add a getter. eg getAmout() that returns the current dollar value.
Setters and getters are meant to be public, else they are pointless.
You could also pass the dollar value in the constructor.
This java program is easy and full of comment,so you can understand it fast.however,why in construct staff[1],the program first go to the statement:
this("Employee #" + nextId, s);
then go to the object initialization block,and then go back to the statement,how confusion.why not it first use the object initialization block
import java.util.*;
public class ConstructorTest
{
public static void main(String[] args)
{
// fill the staff array with three Employee objects
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry", 40000);
staff[1] = new Employee(60000);
staff[2] = new Employee();
// print out information about all Employee objects
for (Employee e : staff)
System.out.println("name=" + e.getName()
+ ",id=" + e.getId()
+ ",salary=" + e.getSalary());
}
}
class Employee
{
// three overloaded constructors
public Employee(String n, double s)
{
name = n;
salary = s;
}
public Employee(double s)
{
// calls the Employee(String, double) constructor
this("Employee #" + nextId, s);
}
// the default constructor
public Employee()
{
// name initialized to ""--see below
// salary not explicitly set--initialized to 0
// id initialized in initialization block
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public int getId()
{
return id;
}
private static int nextId;
private int id;
private String name = ""; // instance field initialization
private double salary;
// static initialization block
static
{
Random generator = new Random();
// set nextId to a random number between 0 and 9999
nextId = generator.nextInt(10000);
}
// object initialization block
{
id = nextId;
nextId++;
}
}
Because this("Employee #" + nextId, s); includes an implicit call to the superclass constructor, which of course must be executed before the initializer block of the subclass.
Using instance initializers is generally a bad idea as they are not well known, cannot do anything more than constructors, and mixing both leads to confusion.
This follows the order specified in section 8.8.7.1 of the JLS:
(Final two bullets)
Let C be the class being instantiated, let S be the direct superclass of C, and let i be the instance being created. The evaluation of an explicit constructor invocation proceeds as follows:
First, if the constructor invocation statement is a superclass constructor invocation,
(Snipped because it's not in our case)
Next, the constructor is invoked.
Finally, if the constructor invocation statement is a superclass constructor invocation and the constructor invocation statement completes normally, then all instance variable initializers of C and all instance initializers of C are executed. (Snip) An alternate constructor invocation does not perform this additional implicit action.
So the instance initializer is executed immediately after the superconstructor is called - which is (implicitly) from public Employee(String n, double s). This should happen before the body of that two-parameter constructor is executed.
Not sure what the actual question is, it's a bit confusing. The order of initialization (static, object, constructor) is predefined and has nothing to do with in which order they appear in the code. As for the general style, I generally discourage using object initialization blocks. It's a very common source of errors, it makes exception-handling more complex and it's hard to debug. In addition, it's not a very common pattern so developers tend to miss looking for it when analyzing bugs.
The Java compiler must ensure that the code in the object initialization block is called from each constructor. For most constructors, it does this by inserting the code into the constructor right after the implicit or explicit call to super(). For compilers that start with this(), however, first of all there is no implicit call to super() -- the other constructor handles that. Secondly, in such a constructor the object initializer block can't be inserted at all, since the code will be picked up when the second constructor is called. Therefore the this() call is the very first thing that happens.