Java Class and Object

Table of Contents

1 Packages

Example to place class inside a package(com.horstman.corejava):

  • add directory, like c:\classdir, to environment variable CLASSPATH which contains one or more directories that are used as roots in a search for .class files.
  • make directory com\horstman\corejava in folder c:\classdir
  • create file in c:\classdir\com\horstman\corejava

    The file name must be the name of the public class in the file followed by .java, so only one public class is allowed in the file.

  • put the name of the package at the top of the file, like package com.horstman.corejava, before the code that defines the classes.

    The package must live in the directory indicated by its name, which must be a directory that is searchable starting from the CLASSPATH.

A class can use all classes from its own package and all public classes from other package. To use public classes in another package, yuo should use import statement or use the full package name.

2 Classes and Objects

Only the primitive types(numbers, characters, and boolean values) are not objects.

Class names are nouns that start with an uppercase letter.

The return value of the new operator is a reference to an object stored in heap.

Classes that cannot be extended are called final classes. If a class is declared final, only the methods, not the fields, are automatically final. A final field cannot be changed after the object has been constructed.

Since you can cast only within an inheritance hierarchy, you should use instanceof to check before casting from a superclass to subclass, by the way, null is not instance of any type, instanceof for null always returns false.

2.1 Access Control

Four access modifiers are

  • private, accessible only in the class itself.
  • default access modifier, accessible in classes in the same package(not in subpackages or enclosing packages) and in the class itself
  • protected, accessible in subclasses of the class, in classes in the same package and in the class itself
  • public, accessible anywhere the class is accessible

The private and protected apply only to members not to classes or interfaces(unless nested). For a member of a class to be accessible, the class must first be accessible.

2.2 Construction and Initialization

Construction has 3 phases:

  • invoking a superclass's constructor
  • initialize the fields using their initializers and any initialization blocks

    It is not allowed in c++.

  • execute the body of the constructor

If you do not initialize a field, it is automatically initilized to default(0, false or null).

The process of creating an object

  • Intialize static field using their initializers and any static block when the class is loaded
    • class is loaded when a static method(including constructors) or a static field of that class is accessed
    • For each subclass, its base class is loaded firstly
  • if it is a creation of new object
    • allocate memory on heap, and clear the memory(0 for numbers, false for boolean, and null for referenes)
    • non-static field initializer and block intialization
    • constructor
class Employee {
  static {
    System.out.println("Employee static block");
  }
    public Employee() {
    System.out.println("Employee constructor");
    }
}

class Manager extends Employee {
  static {
    System.out.println("Manager static block");
  }
    public Manager() {
    System.out.println("Manager constructor");
    }

}
public class Hello {

  public static void main(String[] args) {
    Manager m = new Manager();
  }
  static {
    System.out.println("Hello static block");
  }
}
/* output
Hello static block
Employee static block
Manager static block
Employee constructor
Manager constructor
*/

2.2.1 Constructor

Classes could have constructors, constructors have same name as the class, are not methods and have no return type. Constructor are not inherited. Constructors(including copy constructor) are called with new operator.

constructors can have any of the same access modifier as class member, have annotation. One constructor can invoke another constructor from the same class by using this().

Copy constructor takes an argument of the current object type and constructs the new object to be a copy of the passed in object.

To invoke a superclass's constructor, super(...) should be used as the first statement. To invoke other constructor within the same class(not allowed in c++), this(...) should be used as the first statement. Apparently, they conflicted with each other, but that does not mean, it can skip to run a superclass's constructor by calling other constructor of subclass. Also it is impossible to catch exceptions thrown by them.

The this keyword:

  • denote a reference to the implicit parameter
  • call another constructor for the same class. Like, this(...)

The super keyword:

  • invoke a superclass method. Like, super.method(...)
  • invoke a superclass constructor. Like super(...)

If a constructor neither invoke a superclass's constructor nor invoke other constructor within the same class, the superclass's no-arg constructor is automatically invoked as the first statement.

Constructors should avoid invoking overridable methods, the only safe methods to call inside a constrcutor are those that are final in the base class. This also applies to private methods, which are automatically final.

For a class without constructor declared, a no-argument constructor is provided to set all fieds to their defaullt values(0, false or null). If a class supplies at least one constructor, then no-argument constructor is not given automatically.

2.2.2 Initialization Block

Initialization block can performs initialization of fields, it throws a checked exception only if all of the class's constructors are declared to throw that exception. Multiple blocks executed in the order they appear in the class.

2.2.3 Static Block

Static initialization can performs initialization of static fields, it can not throw any checked exceptions.

2.3 Variables

Variables includes fields, local variables in a code block, and parameters.

Annotations can be applied to any variable declaration. apart from annotations, the only modifier can be applied to local variable(or parameter) is final.

No default initialization value for local variables wheres fields have default initial values.

The keyword final to denote a constant, that is, the final variable cannot refer to another object, but does not means the object referred is constant unless the object is type of primitive or immutable class. A blank final field must be initialized within an initialization block or constructor.

Unlike c/c++, it does not support static local variables. To initialize a static field, either supply an initial value or use a static initialization block. Static initialization occurs when the class is first loaded.

Set up a class constant with the keyword static final.

2.4 Methods

The method header consists of an optional set of modifiers, an optional set of type parameters, the method return type, the signature, and an optional throws clause listing the exceptions thrown by the method. The method signature consists of the method name and the parameter type list enclosed in parenthese. All methods must have a return type and signature.

All methods are defined inside the class itself.

If you try to use local variable before assigning a value, the compiler will refuse to compile the program.

The method modifiers consist of the following:

  • annotations
  • access modifiers
  • abstract, subclass is reponsible for providing a body of a abstract method
  • static, it has no this pointer. it can be called on an object, but not recomended.
  • final
    • For instance methods, it means the method cannot be overridden in a subclass
    • For static methods, it means the method can be hidden
  • synchronized, related to the control of cocurrent threads
  • native
  • strict

An abstract method cannot be static, final, synchronized, or strict. A native method cannot be strict.

The last parameter of a method can be declared as a sequence of parameters of a given type, that is called varargs. For example, String ... is a sequence of zero or more String objects. Whenever a varargs is declared, one may either pass a list of arguments to be implicitly packed into an array, or explicitly pass the array directly.

All parameters to methods are passed "by value".

It can declare method parameters to be final, meaning that the value of the parameter will not change while the method is executing.

Each class can have a main method for convinience to test the class. The main method must be public static void main(String[]). When running a program, the system locates and runs the main method of the program, not all main methods in the involved classes.

Like c++, a method can access the private features of any object of its class.

2.4.1 overloading methods

If a Java base class has a method name that is overloaded several times, redefining that method name in the derived class will not hide any of the base-classs versions(unlike C++). Thus overloading in Java works regardless of whether the method was defined at this level or in a base class.

A fixed-argument method will always be selected over a varargs method. for varargs methods, a sequence parameter T ... is treated as being a parameter of type T[] for overloading purpose. if 2 signature differ only because one declares a sequence and the other an array, then a compile error occurs.

Even differences in the ordering of arguments are sufficient to distinguish two methods.

The signature does not include the return type or the list of thrown exception, and you cannot overload methods based on these factors.

  • find all the methods that have the same name, but different signature
    • the match is attempted without performing any boxing conversions, and without considering the possibility of a variable number of arguments, but considering casting of class type and primitive.
    • if no matches have been found, match is attempted again, but considering boxing conversions.
    • if no matches have been found, the match is attempted again, but considering variable number of auguments.
  • find the best match
    • if any method in the set has parameter types that are all assignable to the corresponding parameters of any other method in the set, then other method is removed from the set because it is a less specific method.
    • if all remaining methods have the same signature then
      • if all are abstract, then one is chosen arbitrarily.
      • if only one is not abstract, then it is chosen.
      • otherwise, the invocation is ambiguous and invalid.

Once a method has been selected, the method determines the expected return type and possible checked exceptions, if they are not acceptable, then you will get a compile error.

2.4.2 Native Method

Native methods can be invoked from java but is written in a "native" language, usually c/c++.

They can be overloaded, overridden, final, static, synchronized, public, protected, or private.

They can be implemented using API provided by the people who wrote the virtual machine.

2.5 Inheritance

All inheritance in Java is public inheritance.

For overriding a method of superclass object, the signature must be identical but the return type can vary in a particular way. if the return type is a reference type, then the overriding method can declare a return type that is subtype of that declared by the superclass method. if the return type is primitive type, then the return type of the overriding method must be identical to that of the superclass method.

For overriding in a varargs method, a sequence parameter of type T... is treated as the same as T[].

The overriding method is also allowed to change method modifiers. the synchronized, native, and strictfp can be freely varied. the overriding method can be final while the superclass method overridden can not be. The overriding method can be abstract even though the superclass method was not. An instance method cannot have the same signature as an inherited static method, and vice versa.

A subclass can change if a parameter in an overriding method is final. The overriding method's exception list can be different from that of the superclass method's as long as every exception type listed in the overriding method is the same as or a subtype of the exceptions listed in the superclass's methods. The exception list of an overriding method can have fewer types listed than the method in the superclass, or more specific types, or both. the overriding method can even have no exception list.

When you override a method, the subclass method must be at least as visible as the superclass method.

Once a method is overriden in a subclass, you cannot invoke it on an instance of the subclass (except from within the subclass, by using the super keyword).

Fields cannot be overridden, they can only be hidden. To access the hidden field of superclass, you can use super, that is similar to access the overriden method of superclass. Also you can access the hidden field by casting the subclass instance to a superclass in which the field is not hidden.

Dynamic binding is the default behavior, but it does not apply on method decorated with private, static or final.

The type of the reference, not the actual class of the object, determines which class's field is accessed. The actual class of object, not the type of the reference, governs which version of the method is called.

class Supershow {
  public String str = "superstr";
  Supershow() { str(); }
  public void show() {
    str();
  }
  public void str() {
    system.out.println("Supershow: " + str);                
  }
}

class Extendshow extends Supershow{
  public string str = "Extendstr";
  Extendshow() {str();}

  public void str() {
       /*a reference to a field always refers to the field declared in the class in which the method is declared,
   or else to an inherited field if there is no declaration in that class*/
     system.out.println("Extendshow: " + str);            
  }
}

public class Hello {    
  public static void main(string[] args) throws Exception {
    Extendshow ext = new Extendshow();
    Supershow sup = ext;

    ext.show();
    sup.show();

    system.out.println("sup.str = " + sup.str);
    system.out.println("ext.str = " + ext.str);
  }
}

/*output
extendshow: null
extendshow: extendstr
extendshow: extendstr
extendshow: extendstr
sup.str = superstr
ext.str = extendstr
*/

A method can be overridden only if it is accessible. If the method is not accessible then it is not inherited, and if it is not inherited it can't be overridden.

Static members within a class, whether fields or methods, cannot be overridden, they are always hidden.

An invocation of super.method always uses the implementation of method the superclass defines(or inherits), it does not use any overriding implementation of that method further down the class hierarchy.

class Base {
  protected string name() {
    return "base";
  }
}

class More extends Base {
  protected string name() {
    return "more";
  }

  protected void printname() {
    Base sref = (Base) this;

    system.out.println("this.name() = " + this.name());
    system.out.println("sref.name() = " + sref.name());
    system.out.println("super.name() = " + super.name());
  }
}

/*output
this.name() = more
sref.name() = more
super.name() = base
*/

2.6 cloning objects

Three important factors in writing a clone method:

  • empty cloneable interface, which you must implement to provide a clone method that can be used to clobe an object.
  • clone method implemented by the Object class, which copy all fields of the original object to the new one, it may need to override the method.
  • CloneNotSupportedException, to signal a class's clone method should not have been invoked.

To override clone method, you need to invoke super.clone() firstly, then write special code to deal with fields for which copying the value is incorrect, like object of type Array, String, or other class.

Ff clone method of a class does not use super.clone(), but use new to create an object of the class, then the extended class's invocation of super.clone() would give an object of the base class, not anobject of the correct, extended type.

Cloning is an alternative form of construction but is not recognized as construction by the system, that means, you have to be aware of using blank finals that can be set only in constructors, but, since Object.clone() will be called eventually, the value of final field will be a copy of the value in the object being cloned.

one advantage the copy constructor has is that it can deal with final fields in situations where clone cannot. Aclass a = new Aclass(objectOfAclass); Aclass a = objectOfAclass.clone();

Serialization can provide a way to make deeper copies than those provided by Object.clone.

2.7 Abstract Class

Abstract classes cannot be instantiated. You still can create object variable of an abstract class, but such a variable should refer to an object of a nonabstract subclass.

In addition to abstract methods, abstract classes can have fields and concrete methods.

A class with one or more abstract methods must itself be declared abstract. A class can even be declared as abstract even though it has no abstract methods.

You can leave some or all of the abstract methods undefined in subclass, then you must tag the subclass as abstrct as well.

2.8 Interface

An interface can extend one or more other interface using extends.

While each class can have only one superclass(Abstract Class belong to class), classes can implement multiple interfaces. Just as you use instanceof to check if an object is of a specific class, you can use it to check if an object implements an interface.

The instanceof operator requires that if both operands are class types, one must be a subtype of the other, otherwise, it will introduce of compile error.

Interface modifiers:

  • annotations
  • public, whithout it, an interface is only accessible within its own package
  • abstract by default
  • strictfp

Reference of interface type can be used only to access members of that interface.

Comparable<point> obj = new Point();
double dist = obj.distance(p1); // invalid: comparable has no distance method

in addition, it can also access method of Object, because no matter what interface the object implements, it is always an Object and so has those methods.

an interface can declare three kinds of members:

  • constants(fields)

    implicitly public static final. must have initializers, blank finals are not permitted.

  • methods

    implicitly abstract and public. cannot be final, static, and other method modifiers.

  • nested classes and interfaces

    implicitly public.

If an interface declares a constant of the same name as an inherited constant, regardless of their types, then the new constant hides the inherited one. the inherited constant can still be accessed through the interface name followd by dot and then the constant name.

the class's own static fields can hide the inherited fields of the interfaces it implements or the class it extends.

As with overriding in class extension, the overriding method is not permitted to throw more checked exceptions than the method it overrides.

The eventual class implementation should provide a method body for each of the overloaded forms.

When overriding, method in subinterface has the same signature as that in superinterface, and return type should be the same(or covariant) as return type of method in superinterface. "the same, or covariant, return type" means, if the return type of subinterface is a reference, then it should be subtype of return type of superinterface's method; if the return type of subinterface is a primitive, then it must be identical to that of superinterface's method. if two inherited methods differ only inreturn type where one type is not a subtype of the other, you will get a compile-time error.

Marker interfaces has neither methods nor constants, just to mark a class as having some general property, but they are important.

Two major different between interfaces and abstract classes:

  • a class can implement multiple interfaces while it can only extends one other class, even if the class is abstract.
  • a abstract class can have a partial implementation, protected parts, static methods, and so on, wheres interfaces are limited to public constants and public methods with no implementation.

2.9 Nested Classes and Interfaces

Normally, you cannot put any code inside an interface, but a nested class can be part of an interface, and any class put inside an interface is automatically public and static.

It does not matter how

2.9.1 Static Nested Types

Static nested classes are members of their enclosing type.

The name of a nested type is enclosingname.nestedname, the nested type is accessible only if the enclosing type is accessible.

For classes, a static nested class or interface could have private, package, protected, or public access. For interfaces, nested type are implicitely public.

Static nested types can access all other members of the enclosing type including private one through an appropriate object reference.

Nested interfaces are always static, by convention, the static modifier is omitted.

2.9.2 Inner Classes

Non-static nested classes are called inner classes, they are associated with instance of a enclosing class.

Inner classes cannot have static members(including static nested types), except for final static fields that are initialized to constants or expressions built up from constants.

Inner classes can extend any other class including its enclosing class, implement any interface and be extended by any other class.

An inner class can be declared final and abstract, and have annotations. Only Inner classes(interfaces) can be private. When protected is applied to an inner class, nothing but outer class, classes in the same package, and the inheritors of the outer class can access the inner class.

A nested class can access all members of its enclosing class, no matter how deeply an inner class may be nested, including private fields and methods without qualification. The enclosing class can access the private members of the inner class, but only by an explicit reference to an inner class object.

If the enclosing class of the inner subclass does not extend the enclosing class of the inner class, or if the inner subclass is not itself an inner class, then an explicit reference to an object of the enclosing class of the inner class must be supplied when the constructor of the inner class is invoked via super in constructor of the enclosing class of the inner subclass. example

class Outer {
  class Inner {}
}

class Unrelated extends Outer.Inner {
  unrelated(Outer ref) {
    ref.super();
  }
}

EnclosingClass.this denotes the outer class reference.

An inner class's own fields and methods(and nested types) can hide those of the enclosing object by two ways:

  • a field or method is declared in the inner class
  • a field or method is inherited by the inner class

An inner class method with the same name as an enclosing class method hides all overloaded forms of the enclosing class method, even if the inner class itself does not declare those overload forms.

Inner classes can be hidden from other classes in the same package.

You must use an object of the enclosing class to make an object of the inner class.

class Outer {
  private int v;

  class Inner{
    public Outer outer(){
      return Outer.this;
    }
    public void g(int i) { v = i; }
  }

  public Inner inner(){
    return new Inner();
  }

  public void f() { System.out.println("v: "+v); }
}

public class Hello {
  public static void main(String[] args) {
    Outer outer = new Outer();
    Outer.Inner inner1 = outer.inner();
    inner1.g(1);
    inner1.outer().f(); // v: 1

    Outer.Inner inner2 = outer.new Inner();
    inner2.g(2);
    inner2.outer().f(); // v: 2
    inner1.outer().f(); // v: 2
  }
}

2.9.3 Local Inner Classes

Local inner classes are defined in code blocks, they are not member of the class of which the code is a part but are local to that block, and completely inaccessible outside the block. They cannot have access modifiers, not can they be declared static. they can have annotations.

They can access all the variables that are in scope where the class is defined, including local variables, method parameters, instance variables, and static variables. The only restriction is that a local variable or method parameter can be accessed only if it is declared final. They can have annotations.

Members of local inner classes can hide the local variables and parameters of the block they are declared in, just as they can hide instance fields and methods. Once a local variable or parameter has been hidden it is impossible to refer to it.

2.9.4 Anonymous Inner Classes

Anonymous classes are defined in the new expression itself, as part of a statement. The type(interface or class) specified to new is the supertype of the anonymous class, and if the supertype is class, then the construction parameters can be given to the superclass constructor.

An anonymous class cannot have an explicit extends or implements clause, nor can it have any modifiers, including annotations. It cannot have explicit construction declared because they have no name to give the constructor. It can have initialization blocks.

Double brace initialization:

//the inner braces are an object construction block
new ArrayList<String>(){{add("Harry"); add("Tony")};};

2.10 Object Class

The Object class is the root of the class hierarchy, and it defines a number of methods, like public boolean equals(Object obj), public int hascode(), protected Object clone() throws CloneNotSupportedException, public final Class<?> getClass(), public String toString(). The equals method implemented in Object class determines if two object references are identical.

The clone method of Object throws an exception if the object does not implement the interface Cloneable. By the way, Object itself does not implements that interface.

If a.equals(b), then a and b must have the same hash code. Example to write the equals method and the hasCode method:

public class Employee
{
   private String name;
   private double salary;
   private Date hireDay;

   public Employee(String n, double s, int year, int month, int day)
   {
      name = n;
      salary = s;
      GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
      hireDay = calendar.getTime();
   }

   @Override public boolean equals(Object otherObject)
   {
      // a quick test to see if the objects are identical
      if (this == otherObject) return true;

      // must return false if the explicit parameter is null
      if (otherObject == null) return false;

      // if the classes don't match, they can't be equal
      if (getClass() != otherObject.getClass()) return false;

      // now we know otherObject is a non-null Employee
      Employee other = (Employee) otherObject;

      // test whether the fields have identical values
      // "==" operator for primitives, Object.equals for object fields
      return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
   }
   // if you redefined the equals method, you should also need to redefine the hasCode method
   @Override public int hashCode()
   {
      return Objects.hash(name, salary, hireDay); 
   }
}

public class Manager extends Employee
{
   private double bonus;

   public Manager(String n, double s, int year, int month, int day)
   {
      super(n, s, year, month, day);
      bonus = 0;
   }

   @Override public boolean equals(Object otherObject)
   {
      // if redefine equals in a subclass, call super.equals
      // and super.equals has checked they belong to the same class.
      if (!super.equals(otherObject)) return false;

      Manager other = (Manager) otherObject;
      return bonus == other.bonus;
   }
   // if you redefined the equals method, you should also need to redefine the hasCode method
   @Override public int hashCode()
   {
      return super.hashCode() + 17 * new Double(bonus).hashCode();
   }
}

For every class, you need to decide if

  • the default clone method is good enough
  • the default clone method can be patched up by calling clone on the mutable subobjects
  • clone should not be attempted

The third option is actually the default. To choose either the first or the second option, a class must

  • implement the Cloneable interface, and
  • redefine the clone method with the public access modifier.

Last Updated 2015-11-14 Sat 20:51.

Created by Howard Hou with Emacs 24.5.1 (Org mode 8.2.10)