I have two classes:
class Base {
public String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Derived extends Base {
public String getValue() {
return name + " foo";
}
}
And an object created:
Base foo = new Base();
foo.setName("John");
Derived bar = (Derived) foo;
This simple example gives ClassCastException exception:
java.lang.ClassCastException: Base cannot be cast to Derived
Is it possible somehow to extend existing object with extra read-only methods ?
With Base foo = new Base(); you're saying that you have a Cat, but all of the sudden you're trying to convert it to Persian cat, which would have succeeded, if all the cats were Persian ones. This is not true and that's why you get a ClassCastException.
You have to do:
Base foo = new Derived();
Cast base object to derived class
You can't cast objects, you can only cast references. The object is unchanged either way.
If you create a Base (new Base), that's all you have. You can't then call your reference to it a Derived because it isn't a Derived, it's a Base. (Which is why you get the ClassCastException: At runtime, the JVM checks what you're referring to to make sure it really can be referred to that way.)
The other direction works:
Derived d = new Derived();
Base b = d;
...because the object that d refers to is a Derived, and Derived extends Base, meaning that it has an is a relationship with Base: All Derived objects are also Base objects.
The converse is not true: All Base objects are not Derived objects. Attempts to treat them as though they were (by casting references) will fail.
You can define a Derived constructor that accepts a Base and copies its state as part of building a new object. But you can't change the type of the actual object; you have to create a new object with equivalent state.
Just pretend:
Derived bar = (Derived) foo;
worked!!!
class Base doesn't have the getValue() method, so
Base foo = new Base();
foo does't have it.
But as bar is a reference of class Derived so you can call bar.getValue().
So, if you call bar.getValue() what will happen (there is no any getValue() in bar) .?
The basic concept is all child class can be treated as a Parent class. Because child class have almost everything which the parent class have.
But as you can add anything later on child class so Parent class object can't be casted to a child class object.
extend existing object
From the basic of OOP object is an instance (real thing) created form a Class (the blue print). If there is a way then it's gonna violate the basic rule.
The core concept of ObjectOrientation is not derivation (or inheritance) but abstraction. It means: If you want that all of your derived Types (classes) have an operation 'genName()' then it is a very good and core idea to have the class Base with this feature. To invoke this method for all of your objects based on class Base, you can use the
Base ref = (Base)anyDerivedObject;
ref.getName();
Thas is a downcast. The compiler checks whether the downcast is possible. It never throws a ClassCastException if Base is really a Base class.
A second fundamental property of ObjectOrientation are virtual operations (methods). It means the derived class can implement the
#Override public String getValue() {
return name + " foo";
}
Please use the #Override annotation in Java for a obvious and safe programming style. If you invoke
ref = getName();
the derived operation of Derived is invoked if the object which is referred by 'ref' is an instance of 'Derived'. That is done with the virtual table or dispatch table which is also present in Java (usual known from C++).
An upcast is:
Derived ref2 = (Derived)ref;
whereby the type of ref is Base, following the example above. The Java-compiler checks whether or not 'Derived' is derived from the type of 'ref', from 'Base'. If it isn't so the compiler forces an error. But if the references are related, the compiler cannot know whether the referenced object is proper. Therefore
Derived bar = (Derived) foo;
from the introducing example fails. The referenced object is not instanceof Derived. That can be only detect on runtime, not on compiletime.
Consider that all Variables in Java are references, never objects itself (excluding the 7 basic types int, short, char etc.). Objects (instances) in Java are always located in the heap and they are referenced in the operations. That is a fundamental concept of Java for safe programming. In C++ there are programming errors possible, which are difficult to find. The calculation time overhead for this concept is not so far.
Related
Consider the following example code
class MyClass {
public String var = "base";
public void printVar() {
System.out.println(var);
}
}
class MyDerivedClass extends MyClass {
public String var = "derived";
public void printVar() {
System.out.println(var);
}
}
public class Binding {
public static void main(String[] args) {
MyClass base = new MyClass();
MyClass derived = new MyDerivedClass();
System.out.println(base.var);
System.out.println(derived.var);
base.printVar();
derived.printVar();
}
}
it gives the following output
base
base
base
derived
Method calls are resolved at runtime and the correct overridden method is called, as expected.
The variables access is instead resolved at compile time as I later learned.
I was expecting an output as
base
derived
base
derived
because in the derived class the re-definition of var shadows the one in the base class.
Why does the binding of variables happens at compile time and not at runtime? Is this only for performance reasons?
The reason is explained in the Java Language Specification in an example in Section 15.11, quoted below:
...
The last line shows that, indeed, the field that is accessed does not depend on the run-time class of the referenced object; even if s holds a reference to an object of class T, the expression s.x refers to the x field of class S, because the type of the expression s is S. Objects of class T contain two fields named x, one for class T and one for its superclass S.
This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used...
So yes performance is a reason. The specification of how the field access expression is evaluated is stated as follows:
If the field is not static:
...
If the field is a non-blank final, then the result is the value of the named member field in type T found in the object referenced by the value of the Primary.
where Primary in your case refers the variable derived which is of type MyClass.
Another reason, as #Clashsoft suggested, is that in subclasses, fields are not overriden, they are hidden. So it makes sense to allow which fields to access based on the declared type or using a cast. This is also true for static methods. This is why the field is determined based on the declared type. Unlike overriding by instance methods where it depends on the actual type. The JLS quote above indeed mentions this reason implicitly:
The power of late binding and overriding is available, but only when instance methods are used.
While you might be right about performance, there is another reason why fields are not dynamically dispatched: You wouldn't be able to access the MyClass.var field at all if you had a MyDerivedClass instance.
Generally, I don't know about any statically typed language that actually has dynamic variable resolution. But if you really need it, you can make getters or accessor methods (which should be done in most cases to avoid public fields, anyway):
class MyClass
{
private String var = "base";
public String getVar() // or simply 'var()'
{
return this.var;
}
}
class MyDerivedClass extends MyClass {
private String var = "derived";
#Override
public String getVar() {
return this.var;
}
}
The polymorphic behaviour of the java language works with methods and not member variables: they designed the language to bind member variables at compile time.
In java, this is by design.
Because, the set up of fields to be dynamically resolved would make things to run a bit slower. And in real, there's not any reason of doing so.
Since, you can make your fields in any class private and access them with methods which are dynamically resolved.
So, fields are made to resolved better at compile time instead :)
I have two classes:
public class Base{
public Derived becomeDerived(){
Derived d = new Derived(this);
//set this pointer pointing to d,
//this = d; doesn't work
return d;
}
}
public class Derived extends Base{
public Derived(Base b){ }
}
Is it possible to change the runtime type of current object by its method as I show in the example?
The reason why I want to do that is providing a method for concatenating objects.
I have
public abstract class Table{
}
and
public class ComplexTable extends Table{ }
which is in fact a linked-list of Table objects.
I would like to provide a method, say Table.append(Table t) which not only modify the current Table object, but also make it ComplexTable's instance.
No.
In your example, Base wouldn't become Derived, it would return a new Derived object.
Base foo = new Base();
foo = foo.becomeDerived();
This is likely what's throwing you off, remember that the variable is not the object, just a reference to one. So while you can say foo changes from Base to Derived, the run-time type of an object didn't change, you made a new object with a different run-time type and reassigned the variable.
Edit: More in depth example. I give the objects "names" just so it's easier to understand.
Base foo = new Base();
/* After execution:
*
* Vars: | Objects:
* foo ----+---> a Base object (Name: Joe)
*/
foo = foo.becomeDerived();
/* After execution:
*
* Vars: | Objects:
* foo ----+---> a Derived object (Name: Phil)
* | a Base object (Name: Joe)(notice nothing references it)
*/
The type of "Joe" did not change. Joe was and will always be a Base object. This is what you're referring to by "run-time type of an object." However, the run-time type of variables change all the time! In this example, foo starts as Base but becomes Derived.
You cannot set this to d as this is super type of Derived d.
But it is possible to store object of type Derived like d in this case into a reference of Type Base.
You can store types of derived classes in reference of base class. But it is not changing types technically just reference holding object of derived type.
Unlike in C++
You can not change or reassign the value of this.
This was chosen to be a reserved word.So Answer is
No ,it is not possible to change the runtime type of current object
.
One more error i could find in your code is always use the Base reference variable so you can refer to objects of classes extending it.
Base b;
b=new Derived();
b=new Base();
Bad idea follows
It is possible to change the type of an object, but it relies on behaviour that is not part of the JVM spec and is thus not portable. You have been warned.
There is a class sun.misc.Unsafe that let's you read/write memory at any offset of an object. The type of an object is stored in the object's header at offset 8 on 64-bit JVMs. Thus, to change the type of the object all you need to do is to change the value at this offset. Note that the types/classes your switching between must have the same structure (reference fields on the same offsets and having the same total size). If not, the garbage collector will read non-references as references (or vice-versa) and crash you JVM.
I'm not providing working example intentionally as I'm not recommending this. Stuff like this is more suitable in C than in Java. It's really not that hard to do though, and the link I've provided together contains all information required.
Some tests I made indicates that it works on several JVMs and that the JIT is robust against these dangerous object type changes. That is no promise that it works in all systems and under all conditions.
By the way, I'm curious to hear from someone who can explain why the JIT doesn't consider the type of an object as a jit-compile-time constant, or how the JIT knows to recompile when the type of an object has changed.
In a nutshell, how and why is this possible:
Object obj=new MyClass();
Object is the superclass of all objects, therefore MyClass is a child class of Object. In general, in Java, Why is it possible to use the constructor of a child class in the parent class?
I understand how it could go the other way around, since the child has all the variables/methods of the parent class, so when you initialize them you are just initializing the variables specified in the parent constructor, that exist by definition in the child. The problem is, when you go the other way around, it is not necessarily true. A child can have variables the parent doesn't, so how is it possible to use the child constructor with the parent, when the parent does not even have the variables in the first place?
What uses does this feature have in development? I would think that if you want an instance of class B, you would declare it as B thing=new B(), and not A thing=new B(). This is probably my inexperience talking, so I would appreciate enlightenment on why and how a parent class can be initialized as one of its children.
Why is it possible to use the constructor of a child class in the
parent class?
This is not correct. When you do
Object obj = new MyClass();
Object obj; declares a reference of the type Object
and new MyClass(); returns a reference to the object it created.
So, you are instantiating a MyClass and assigning the reference to the object created to a reference of the type Object, and this is possible because MyClass is an Object.
As you say,
A child can have variables the parent doesn't
That's called extending the parent functionality (inheritance).
For your second question think about the classic Animal example: Suppose you create a Animal class and you create a method makeSound() on it.
Now you create two subclasses of Animal, Dog and Cat, that overrides the makeSound()method of Animal (a Dog barks and a Cat meows).
Imagine that you represent a room full of Animals (Dogs and Cats) using a List, and you want to make all of them makeSound(). Your list will be declared as List<Animal> because you don't know the kind of Animals that you will store.
And then you iterate over the List to call makeSound() for each Animal. It doesn't matter if the Animal is a Dogor a Cat, it will make it's sound.
And then imagine you want to add Birds to the List. Easy, isn't it?
You are thinking in terms of C++ semantics, but this is Java. In Java, all non-primitive type variables are references, not instances.
In C++, when you say
Object obj;
you allocate a new Object instance on stack or in static memory.
When you say
Object obj = new MyObject;
you invoke a constructor of Object class that takes MyObject pointer (or may be something else that MyObject can be converted to).
In Java,
Object obj;
does not create any instances of Object. It simply creates a variable that can have a reference to an Object instance, but at the moment does not refer to any. It is initialized to null.
Object obj = new MyObject();
allocates an instance of MyObject. It does not allocate a new instance of Object. It simply sets the variable to refer to the new instance. In C++ terms this is much more similar to
Object *obj = new MyObject();
So we're not constructing a parent instance from child instance. We're changing a value the variable is set to, from null to a new child instance.
First, you must get a clear understanding of things. Your example expression:
Object obj = new MyClass(); is actually a compound of two elementary operations.
The first one is creating an instance of MyClass: new MyClass(). The new keyword is basically the only way of actually obtaining an instance of a class (lets ignore runtime reflection to keep this simple), and you are literally naming what you want to create (MyClass) here by its constructor. There is no way to create anything other than what you literally named with the new keyword. The result of new is (implicitly) an instance of MyClass, but the explicit result of a new X is a reference of type X (the reference referring to the newly created instance).
Now the second operation is assigning the reference to your (new) MyObject to another reference of type Object. And this is valid because MyObject is an Object (due to inheritance).
Why would you need this?
This is an essential feature to actually make use of polymorphism. The ability to refer to any child class as its superclass is what makes polymorphism so powerful. You basically will use it everywhere where there is an aspect common to two classes, but there are also differences.
A real world example would be graphical user interfaces. There are buttons, lists, tables and panels in a window, which are all user interface elements, but each does a different thing. To present them neatly organized in a window, these elements are often nested into panels, more abstractly said into containers. Now a container doesn't care what kind of elements go into it, as long as they are components. But to handle them properly a container does need some basic information about these components, mostly how much space they occupy and how to actually draw them. So this is modelled as something like:
public abstract class Component {
public int getWidth() { ... }
public int getHeight() { ... }
public void paint(Graphics g) { ... }
}
public class Container extends Component {
public void add(Component child) { ... }
public void paint(Graphics g) {
for (Component child : children) {
child.paint(g);
}
}
}
Thats almost straight lifted out of the JDK, the point is, if you needed to refer to each Component as its concrete type, it would be impractical to build a Container, it would need extra code for each Component you decide to make (e.g. there would be an addButton, addTable and so on). So instead, Container just works with reference to Component. No matter what Component is created (e.g. Button, CheckBox, RadioButton etc.), since Container just relies on them to all be Component's, it can handle them.
Every class in Java is descended from Object. So MyClass is an Object, by definition, but a more specialized version of it. Think of it like this: every living creature is an Animal. A Cat is a special kind of animal; a specific type. Since the Cat is an Animal, you can still just call it an Animal:
Animal a = new Cat();
But doing so, with a, you can't do anything specific to a Cat, like meow() or purr(), but you can call methods which are valid for all Animals, such as breathe().
HTH
class myMobile{
public void call{
System.out.println("Mobile");
}
}
public class mainClass{
public static void main(){
Object o=new myMobile();
//here we can call methods which are common to all
// objects not specific to
// myMobile object
}
}
Because a MyClass is a Object. Note that java is special because Object is the superclass of every other class type (there is no equivalent in C++).
A more interesting example would be if you had a class or interface and one or more subclasses. This comes up all the time in OOD. Consider for example java's jdbc API: a common set of interfaces to connect and query a database that can be implemented by different concrete classes. You only need to code to the API and then at runtime use the implementation for your DB of choice.
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
i.e. every Java class is an Object. This is why.
http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
The Object class, defined in the java.lang package, defines and implements behavior common to all classes—including the ones that you write. In the Java platform, many classes derive directly from Object, other classes derive from some of those classes, and so on, forming a hierarchy of classes.
You have two separate things here:
The construction of a new instance
The assignment of that instance to
a variable
Since your instance of MyClass is also an instance of Object, this works well.
Consider the following, generic situation:
class A extends B implements C,D {
}
As your A is a B and also a C and a D and an Object, once you created an instance, you can (directly or indirectly) assign it to variables of all those types:
A a = new A();
B b = a;
C c = a;
D d = a;
Object o = a;
Your view on the fields or methods is limited by the type of the variable (i.E. as variable of type C, you only see the methods declared by C).
Nevertheless, your instance is always of the type you instanciated using the constructor, regardless of the variable type.
Answering a question here at SO, I came up to a solution which would be nice if it would be possible extend the Class class:
This solution consisted on trying to decorate the Class class in order to allow only certain values to be contained, in this case, classes extending a concrete class C.
public class CextenderClass extends Class
{
public CextenderClass (Class c) throws Exception
{
if(!C.class.isAssignableFrom(c)) //Check whether is `C` sub-class
throw new Exception("The given class is not extending C");
value = c;
}
private Class value;
... Here, methods delegation ...
}
I know this code does not work as Class is final and I wonder why Class is final. I understand it must have to do with security but I can't imagine a situation where extending Class is dangerous. Can you give some examples?
By the way, the closer solution for the desired behavior I can reach is:
public class CextenderClass
{
public CextenderClass(Class c) throws Exception
{
if(!C.class.isAssignableFrom(c)) //Check whether is `C` sub-class
throw new Exception("The given class is not extending C");
value = c;
}
public Class getValue() {
return value;
}
private Class value;
}
But it lacks the beauty of transparent decoration.
According to comments in the Class class Only the Java Virtual Machine creates Class
objects..
If you were allowed to extend classes, then a problem would arise, should you be allowed to create custom Class objects?. If yes, then it would break the above rule that only the JVM should create Class Objects. So, you are not given that flexibility.
PS : getClass() just returns the already created class object. It doesn't return a new class object.
That's a very good question but is only an instance of a more general problem and although #TheLostMind 4 years ago has just responded (considered an implementation point of view) in terms of JVM rules/restrictions the problem still remain: why JVM pose that rules? There have to be a plausible reason. We have to examine it from a more abstract level(point of view)
Short answer:
Plausibly all that has to do with type safety and as all we know Java is a strongly typed language and permits no one to change that fact.
Elaborate Answer(with some context so to be understandable for everyone):
All the story start from static and dynamic binding.
The flexibility given by subtype polymorphism makes the declared (static) type of an object in general different from its run-time (dynamic) type.
The run-time type is in general a subtype of the static type.
e,g.
AClass a = new AClass();
AsubClass b = new AsubClass(); // AsubClass is derived from AClass
a=b;
The static type of a is AClass and after the assignment a=b; its runtime type is AsubClass. This has implications on selection of the most appropriate method when executing a message.
Now consider the class Vehicle given
below.
public class Vehicle {
private int VIN; // Vehicle Identification Number
private String make;
public boolean equals(Object x) {
return (VIN == (Vehicle)x.VIN);
}
// other methods
}
The method equals in the root class java.lang.Object is defined as the test on object identity.
This is the only meaningful way of defining the equality of objects in general.
That is, two objects are equal if they have the same identity.
In a specific class a more suitable meaning of equality may be more appropriate. In the above class two vehicles are considered equal if their VINs (vehicle identification numbers) are equal.
So the method equals is redefined accordingly in the
class Vehicle. This redefinition of an inherited
method is called overriding.
Note that the signatures of the inherited method arguments are required to remain the same in the subclass according to the function subtyping rule.
This creates an awkward situation because in the class Vehicle we would like to refer to the VIN field of the argument, and Object does not have such a field. This is why the type cast (Vehicle)x specifies that the intent is to view x as a Vehicle. There is no way to
verify this cast statically, hence a dynamic check is generated by the compiler. This is an instance of dynamic type checking.
In order for overriding to work correctly the method to be invoked is determined by the dynamic type of the receiver object (also known as dynamic dispatch (selection) of methods and is the most important case of dynamic binding in OO languages.)
e.g.
Object a = new Object();
Object b = new Object();
Vehicle aV = new Vehicle();
Vehicle bV = new Vehicle();
a=aV;
b=bV;
. . .
a.equals(b)
. . .
The method to be invoked in response to the message a.equals(b) will be the method equals overridden in the class Vehicle because the run time type of a is Vehicle.
There are situations in which overriding a method might be problematic and should not be allowed. A good example is the Java.lang.Object 's getClass() . This method has a particular implementation in the underlying virtual platform, which guarantees that invocation of this method will indeed return the class object of the receiver of the method.
Allowing overriding would have serious implications on the intended semantics of this method creating nontrivial problems in dynamic type checking. This is probably why the getClass() is declared as final.
e.g.
public class Object {
public final Class getClass();
....
}
Finally The class Class in Java is final, i.e. cannot be extended, and hence none of its methods can be overridden. Since the class Class has only introspection methods, this guarantees safety of the type system at run-time, i.e., the type information cannot be mutated at run time.
to extend the concept a bit more ...
Dynamic dispatch (selection) of methods based on the type of the receiver object is the basic technique in object-oriented languages.
It brings the type of flexibility that makes the whole object-oriented paradigm work.
Adding new types by inheritance to an already compiled and running application requires only compilation and linking of the newly introduced types without recompiling the existing application. However, this flexibility comes with some penalty in efficiency because the decision about method selection is postponed to runtime. Modern
languages have efficient techniques for dynamic dispatch of methods, but some languages like C++ and C# try to avoid the associated cost by providing a static binding (method selection) option. In C#, methods are statically bound unless they are explicitly declared as virtual.
e.g.
public class Object {
public virtual boolean equals(Object x);
// other methods
}
Overriding this method in C# will be indicated by an explicit keyword override.
e.g.
public class Vehicle {
private int VIN;
private String make;
public override boolean equals(Object x) {
return (VIN == (Vehicle)x.VIN);
}
// other methods
}
Methods whose receiver is the class object are always bound statically.
The reason is that there is only one class object for all objects of that class. Since the receiver is known at compile time, there is no need to postpone method selection to run time. These methods are thus declared as static to indicate that they belong to the class itself.
An example is the method numberOfVehicles of the class Vehicle The number of vehicles is not the property of individual vehicle objects. It is the
property of all objects of the class Vehicle, hence it belongs to the class itself.
e.g.
public class Vehicle {
// fields;
public static int numberOfVehicles();
// other methods
}
We can summarize all the above discussion as follows:
– The basic mechanism for selecting a method for executing a message (method
dispatch) in object-oriented languages is dynamic. It is based on the run-time type of the receiver object.
– The receiver of a static (i.e. class) method is the class object. Since there is only
one class object of a given type, selection of a static method is static.
– Some languages (C++ and C#) allow a choice of static versus dynamic method dispatch. Although this is done for the reasons of efficiency, it has been shown that when both dispatch mechanisms are used in a program, that may obscure the
meaning of the program.
Let's say you have some Java code as follows:
public class Base{
public void m(int x){
// code
}
}
and then a subclass Derived, which extends Base as follows:
public class Derived extends Base{
public void m(int x){ //this is overriding
// code
}
public void m(double x){ //this is overloading
// code
}
}
and then you have some declarations as follows:
Base b = new Base();
Base d = new Derived();
Derived e = new Derived();
b.m(5); //works
d.m(6); //works
d.m(7.0); //does not compile
e.m(8.0); //works
For the one that does not compile, I understand that you are passing in a double into Base's version of the m method, but what I do not understand is... what is the point of ever having a declaration like "Base b = new Derived();" ?
It seems like a good way to run into all kinds of casting problems, and if you want to use a Derived object, why not just go for a declaration like for "e"?
Also, I'm a bit confused as to the meaning of the word "type" as it is used in Java. The way I learned it earlier this summer was, every object has one class, which corresponds to the name of the class following "new" when you instantiate an object, but an object can have as many types as it wants. For example, "e" has type Base, Derived, (and Object ;) ) but its class is Derived. Is this correct?
Also, if Derived implemented an interface called CanDoMath (while still extending Base), is it correct to say that it has type "CanDoMath" as well as Base, Derived, and Object?
I often write functions in the following form:
public Collection<MyObject> foo() {}
public void bar(Collection<MyObject> stuff){}
I could just as easily have made it ArrayList in both instances, however what happens if I later decide to make the representation a Set? The answer is I have a lot of refactoring to do since I changed my method contract. However, if I leave it as Collection I can seamlessly change from ArrayList to HashSet at will. Using the example of ArrayList it has the following types:
Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess
There are a number of cases where confining yourself to a particular (sub)class is not desired, such as the case you have where e.m(8.0);. Suppose, for example, you have a method called move that moves an object in the coordinate graph of a program. However, at the time you write the method you may have both cartesian and radial graphs, handled by different classes.
If you rely on knowing what the sub-class is, you force yourself into a position wherein higher levels of code must know about lower levels of code, when really they just want to rely on the fact that a particular method with a particular signature exists. There are lots of good examples:
Wanting to apply a query to a database while being agnostic to how the connection is made.
Wanting to authenticate a user, without having to know ahead of time the strategy being used.
Wanting to encrypt information, without needing to rip out a bunch of code when a better encryption technique comes along.
In these situations, you simply want to ensure the object has a particular type, which guarantees that particular method signatures are available. In this way your example is contrived; you're asking why not just use a class that has a method wherein a double is the signature's parameter, instead of a class where that isn't available. (Simply put; you can't use a class that doesn't have the available method.)
There is another reason as well. Consider:
class Base {
public void Blah() {
//code
}
}
class Extended extends Base {
private int SuperSensitiveVariable;
public setSuperSensistiveVariable(int value) {
this.SuperSensistiveVariable = value;
}
public void Blah() {
//code
}
}
//elsewhere
Base b = new Extended();
Extended e = new Extended();
Note that in the b case, I do not have access to the method set() and thus can't muck up the super sensitive variable accidentally. I can only do that in the e case. This helps make sure those things are only done in the right place.
Your definition of type is good, as is your understanding of what types a particular object would have.
What is the point of having Base b = new Derived();?
The point of this is using polymorphism to change your implementation. For example, someone might do:
List<String> strings = new LinkedList<String>();
If they do some profiling and find that the most common operation on this list is inefficient for the type of list, they can swap it out for an ArrayList. In this way you get flexibility.
if you want to use a Derived object
If you need the methods on the derived object, then you would use the derived object. Have a look at the BufferedInputStream class - you use this not because of its internal implementation but because it wraps an InputStream and provides convenience methods.
Also, I'm a bit confused as to the meaning of the word "type" as it is used in Java.
It sounds like your teacher is referring to Interfaces and Classes as "types". This is a reasonable abstraction, as a class that implement an interface and extends a class can be referred to in 3 ways, i.e.
public class Foo extends AbstractFoo implements Comparable<Foo>
// Usage
Comparable<Foo> comparable = new Foo();
AbstractFoo abstractFoo = new Foo();
Foo foo = new Foo();
An example of the types being used in different contexts:
new ArrayList<Comparable>().Add(new Foo()); // Foo can be in a collection of Comparable
new ArrayList<AbstractFoo>().Add(new Foo()); // Also in an AbstractFoo collection
This is one of the classic problems on object oriented designs. When something like this happens, it usually means the design can be improved; there is almost always a somewhat elegant solution to these problems....
For example, why dont you pull the m that takes a double up into the base class?
With respect to your second question, an object can have more than one type, because Interfaces are also types, and classes can implement more than one interface.