CompSci 230 S2 2015 Software Design and Construction Packages & Binding Agenda & Reading Topics: Packages Access Modifiers Static & Dynamic Binding Casting Reading The Java Tutorial 2 Creating and Using Packages Controlling Access to Members of a Class Overriding and Hiding Methods Hiding Fields 06 Packages Definition: A package is a grouping of related types providing access protection and name space management. Purpose: “To make types easier to find and use, to avoid naming conflicts, and to control access, programmers bundle groups of related types into packages.” Conceptually you can think of packages as being similar to different folders on your computer. Note that types refers to classes, interfaces … Examples: 3 A package is a namespace that organizes a set of related classes and interfaces.” java.io — file operations java.lang — basic language functionality and fundamental types java.util — collection data structure classes java.awt — basic hierarchy of packages for native GUI components 06 Creating a Package “To create a package, you choose a name for the package (folder) and put a package statement with that name at the top of every source file that contains the types that you want to include in the package. Rules: package X; There can be only one package statement in each source file, and must be the first line in the source file. If you put multiple types in a single source file, only one can be public, and it must have the same name as the source file. You can include non-public types in the same file as a public type This rule makes it easy for the class loader, and the human programmer, to find the definition for a public type. 4 06 One public type per file! “If you put multiple types in a single source file, only one can be public, and it must have the same name as the source file. For example, you can “You can include non-public types in the same file as a public type (this is strongly discouraged, unless the non-public types are small and closely related to the public type), but only the public type will be accessible from outside of the package. All the top-level, non-public types will be package private.” This rule makes it easy for the class loader, and the human programmer, to find the definition for a public type. 5 define public class Circle in the file Circle.java, define public interface Draggable in the file Draggable.java, define public enum Day in the file Day.java, and so forth. The name of a package determines the directory in which the files of this package should be stored. The name of a public type determines the name of the file in which the type’s definition must be found.” 06 The default package “If you do not use a package statement, your type ends up in an unnamed package. 6 Generally speaking, an unnamed package is only for small or temporary applications or when you are just beginning the development process. Otherwise, classes and interfaces belong in named packages.” 06 Package naming conflicts “With programmers worldwide writing classes and interfaces using the Java programming language, The fully qualified name of each Rectangle class includes the package name. 7 it is likely that many programmers will use the same name for different types. The compiler allows both classes to have the same name if they are in different packages. That is, the fully qualified name of the Rectangle class in the graphics package is graphics.Rectangle, and the fully qualified name of the Rectangle class in the java.awt package is java.awt.Rectangle. 06 External references To use a public package member from outside its package, you must do one of the following: The fully qualified name for class C in package p is p.C To import class C from package p, you write import p.C To import an entire package p, you write import p.* package p1; public class Protection { int n_default = 1; public int n_public = 2; protected int n_protected = 3; private int n_private = 4; } public class Class1 { public static void main(String[] args) { p1.Protection c = new p1.Protection(); } } 8 06 Access Modifiers Classes, and their fields and methods have access levels to specify how they can be used by other objects during execution A private field or method is accessible only to the class in which it is defined. A protected field or method is accessible to the class itself, its subclasses, and classes in the same package. A public field or method is accessible to any class of any parentage in any package Private Protected Public Default Class itself YES YES YES YES Other Subclasses within a package No YES YES YES Other classes within a package No YES YES YES Other subclasses outside this package No YES YES No Other classes outside this package No No YES No 9 06 Example: subclasses within a package package p1; public class Protection { int n_default = 1; public int n_public = 2; protected int n_protected = 3; private int n_private = 4; } p2 OtherPackage P2Derived p1 Protection Derived SamePackage Within a package package p1; public class Derived extends Protection { public static void main(String[] args) { Derived b = new Derived(); System.out.println("n_default=" + b.n_default); System.out.println("n_public=" + b.n_public); System.out.println("n_protected=" + b.n_protected); // System.out.println("n_private" + b.n_private); } } C:/06/access> javac p1/*.java java p1.Derived No access to Private variable n_default=1 n_public=2 n_protected=3 Example: p1/Derived.java 10 06 Example: Other classes within a package package p1; public class Protection { int n_default = 1; public int n_public = 2; protected int n_protected = 3; private int n_private = 4; } p2 OtherPackage P2Derived p1 Protection SamePackage Derived With a package n_default=1 n_public=2 n_protected=3 package p1; public class SamePackage { public static void main(String[] args) { Protection b = new Protection(); System.out.println("n_default=" + b.n_default); System.out.println("n_public=" + b.n_public); System.out.println("n_protected=" + b.n_protected); No access to // System.out.println("n_private" + b.n_private); Private variable } } Example: p1/SamePackage.java 11 C:/06/access> javac p1/*.java java p1.SamePackage 06 Example: subclasses outside this package package p1; public class Protection { int n_default = 1; public int n_public = 2; protected int n_protected = 3; private int n_private = 4; } p2 OtherPackage P2Derived Different packages Protection Derived p1 SamePackage n_public=2 n_protected=3 package p2; public class P2Derived extends p1.Protection { No access to the public static void main(String[] args) { default variable P2Derived b = new P2Derived(); //System.out.println("n_default=" + b.n_default); System.out.println("n_public=" + b.n_public); System.out.println("n_protected" + b.n_protected); No access to //System.out.println("n_private" + b.n_private); Private variable } } C:/06/access> javac p1/*.java javac p2/*.java java p2.P2Derived Example: p2/P2Derived.java 12 06 Example: Other classes outside this package package p1; public class Protection { int n_default = 1; public int n_public = 2; protected int n_protected = 3; private int n_private = 4; } p2 OtherPackage P2Derived Different packages Protection Derived p1 SamePackage n_public=2 package p2; No access to public class OtherPackage { - Default public static void main(String[] args) { - protected p1.Protection b = new p1.Protection(); - private // System.out.println("n_default=" + b.n_default); System.out.println("n_public=" + b.n_public); // System.out.println("n_protected" + b.n_protected); // System.out.println("n_private" + b.n_private); } } C:/06/access> javac p1/*.java javac p2/*.java java p2.OtherPackage Example: p2/OtherPackage.java 13 06 Statically or Dynamically typed Programming languages generally offer some sort of type system, and can be described as being either statically typed or dynamically typed With a statically typed language, compile-time checks are carried out to determine whether variable usage is valid Java int x = 10; x = "Hello"; In a dynamically typed language, variables are not associated with a type and are simply names that can be assigned arbitrary values Python x = 10; x = "Hello"; 14 06 Java - statically typed language Every variable name is bound both to a static type (static type at compile time, by means of a data declaration) and static dynamic type to an object (dynamic type) or null type the classes of object to which the variable can refer the message that can be sent using the variable Restrictions are checked at compile-time 15 Ball b1 = new Ball(...); Ball b2 = null; The type imposes restrictions on how a variable can be used. The type restricts: The binding to an object is optional. The compiler will not issue code if it detects a violation. Java is a “type-safe” language: its compile-time checking restricts the amount of damage that can be done by careless or malicious programmers. 06 Static Typing Restrictions A reference variable of static type T can refer to an instance of class T or to an instance of any of T’s subclasses 16 In other words, an instance of class T can always be substituted for an instance of any subclass of T Through a reference variable of static type T, the set of messages that can be sent using that variable are the methods defined by class T and its superclasses A variable’s static type is fixed at compile time but its dynamic type may vary at run-time. 06 Example: instance_var/Derived.java Static Binding: Instance Variables class Base { public int x = 10; } public class Derived extends Base { public int y = 20; } instance variable x in Base //Case 1: Base b1 = new Base(); System.out.println("b1.x=" + b1.x); Base b1-> x=10 From superclass Derived b2-> x=10 //Case 2: Derived b2 = new Derived(); System.out.println("b2.x=" + b2.x); System.out.println("b2.y=" + b2.y); instance variable x : inherited from Base y=20 instance variable y in Derived b3 is declared as type Base, static type = base; dynamic type = Derived //Case 3: Base b3 = new Derived(); System.out.println("b3.x=" + b3.x); //System.out.println("b3.y=" + b3.y); Base b3-> x=10 There is no y declared in Base class -> compile error! y=20 Note: 17 instance variable x : inherited from Base, Access to fields is governed by the form of the reference 06 Example: shadow/Derived.java Static Binding – Hiding a Field Within a class, a field that has the same name as a field in the superclass hides the superclass's field class Base2 { public int x = 10; } instance variable x in Base //Case 1: Base2 b1 = new Base2(); System.out.println("b1.x=" + b1.x); public class Derived2 extends Base2 { public int x = 20; } Base b1-> x=10 Derived b2-> x=10 //Case 2: instance variable x from Derived (20) Derived2 b2 = new Derived2(); System.out.println("b2.x=" + b2.x); b3 is declared as type Base instance variable x from Base, (10) //Case 3: Base2 b3 = new Derived2(); System.out.println("b3.x=" + b3.x); x=20 Base b3-> x=10 x=20 Note: 18 Access to fields is governed by the form of the reference 06 Get the hiding values Within the subclass, the field in the superclass cannot be referenced by its simple name To "unshadow" it by referring to super.x method In the public class Derived extends Base { subclass ... public void method1() { System.out.println("x from Derived:" + x); System.out.println("x from superclass: " + super.x); ... Note: 19 this.x access the field name x, defined in the child class super.x access the field name x, defined in a parent class super.super.x is not valid x was not specified as private. 06 Example: static_var/Derived.java Static Binding - Static Variables class Base { public static int x; public Base() { x++; } } public class Derived extends Base { public static int y; public Derived() { y++; } } class variables: one copy only //Case 1 Base b1 = new Base(); System.out.println("Base.x=" + Base.x); System.out.println("Derived.y=" + Derived.y); 1 0 class variable x : inherited //Case 2 from Base Derived b2 = new Derived(); System.out.println("Base.x=" + Base.x); System.out.println("Derived.x=" + Derived.x); System.out.println("Derived.y=" + Derived.y); //case 3 Base b3 = new Derived(); System.out.println("Derived.x=" + Derived.x); System.out.println("Derived.y=" + Derived.y); Note: 20 2 2 1 3 2 Base: x= 0->1 Derived: y= 0 b1 Base: x= 0->1->2 Derived: y= 0 ->1 b1 b2 Base: x= 0->1->2->3 Derived: y= 0 ->1->2 b1 b2 b3 Access to fields is governed by the form of the reference One copy only, all instances of the class share the same static variable Class variable can be accessed before an object of a class is created, and without reference to a particular object 06 Example: static_method/Derived.java public class Derived extends Base { public static int y=2; Static Methods class Base { public static int x=1; public static int getY() { return y; } public static int getX() { return x; } public static int getX() { return 10; } } } Base b1 = new Base(); Base b2 = new Derived(); Invoke getX in Base System.out.println("b1.getX()=" + b1.getX()); 1 1 Invoke getX in Base No Overriding for static method System.out.println("b2.getX()=" + b2.getX()); //System.out.println("b2.getY()=" + b2.getY()); Compile error No getY in Base System.out.println("Derived.x=" + Derived.getX()); System.out.println("Derived.y=" + Derived.getY()); Invoke getX and getY in Derived 10 2 Note: 21 Static methods can only invoke other static methods and access other static variables Only the non-static methods of a class can be overridden 06 Dynamic Binding Dynamic Binding refers to the case where compiler is not able to resolve the call and the binding is done at runtime only. A call of that method (method1) can only be resolved at runtime as the compiler can't be sure of what type of object this reference would be pointing to at runtime. The search for a method begins with the dynamic class. If this class doesn’t implement the method (i.e. it doesn’t introduce or override the method), the search progresses to it’s superclass. This process is repeated up the hierarchy until the method is found. Derived b2 = new Derived(); Base b3 = new Derived(); Dynamic class b2.f(); b2.g(); b2.h(); 22 f() in Derived, f() in Base? Invoke f() in Base g() in Derived? Invoke g() in Derived h() in Derived? Invoke h() in Derived b3.f(); b3.g(); b3.h(); f() in Base? Invoke f() in Base g() in Base? Invoke g() in Derived h() in Base? Compile time error class Base { public void f() { ... } public void g{} { ... } } public class Derived extends Base { public void g{} { ... } public void h() { ... } } 06 Casting Casting an object to a different type will permit access to fields shadowed by the type of the original object Casting an object to a different type will have NO effect on which method is invoked in response to a given message. Once overridden, methods remain overridden To cast, just precede a value with the parenthesised name of the desired type A ClassCastException is thrown if the type cast is incompatible with the type of object to be pointed to. To check that a potential cast is safe, the instanceof operator should be used The instanceof operator Can be used to determine the type of an object Returns true if <obj> can be assigned into a reference of type <Class name>. That is, instanceof checks if the <obj> is-an instance of the specified class, provided obj is not null. Derived d = (Derived) b3; Base b4 = (Base) b4; 23 <obj> instanceof <Class name> 06 Example: casting/Primitive.java Wider type Primitive Types Widening conversions Wider assignment Wider Casting Casting needed Casting a value to a wider value is always permitted but never required. However, explicitly casting can make your code more readable double d = 4.9; int i = 10; double d1, d2; Assignment conversion d1 = 10.0 d1 = i; d2 = (double) i; Narrowing conversion Narrow assignment – Compile-time error Narrow Casting – Loss of information You must use an explicit cast to convert a value in a large type to a smaller type, or else converting that value might result in a loss of precision. double d = 4.9; int i = 10; int i1, i2; 24 Casting conversion (optional) d2 = 10.0 //i1 = d; i2 = (int) d; Assignment conversion Compile-time error Narrow Casting: i2=4 NOTE: Everything beyond the decimal point will be truncated 06 Example: casting/CastObject.java Object Types Widening conversions Wider object reference assignment conversion Wider object reference casting (optional) Base b = new Base(); Derived d = new Derived(); Base b1, b2; System.out.println(d.y); Note: 25 Wider type Base Derived Assignment conversion - OK However, no access to fields in Derived b1 = d; //System.out.println(b1.y); Widening Casting conversion - OK However, no access to fields in Derived b2 = (Base) d; //System.out.println(b2.y); Reference conversion, like primitive conversion, takes place at compile time, because the compiler has all the information it needs to determine whether the conversion is legal Inheritance relation is an “is a” relation; the parent object is more general than child object The general rule of thumb is that converting to a superclass is permitted (because super class is wider than sub class) 06 Wider type Object Types Person Example: casting/CastObject.java Student Narrowing conversion Narrow object reference assignment – Compile-time error Narrow object reference casting – Compile-time OK, Run-time? Like primitive casting: By using a cast, you convince the compiler to let you do a conversion that otherwise might not be allowed The run-time check determines whether the class of the object being cast is compatible with the new type Base b = new Base(); Derived d = new Derived(); Derived d1, d2, d3; //d1 = b; Compile-time error d2 = (Derived) b; Base b-> x=10 Compile-time OK, Run-time ERROR b is an instance of class Base, not Derived java.lang.ClassCastException: Base Base d_as_b = new Derived(); d3 = (Derived) d_as_b; Base d_as_b-> x=10 26 y=20 Compile-time OK, narrow casting, casting from superclass to subclass Run-time OK d_as_b is an instance of Derived 06 Example: Casting/Recover.java Using Casting Shadowing Using type casting, it is possible to recover a hidden member (class variable, class method, or an instance variable), but not an overridden method (i.e. an instance method). An overridden method can be recovered only by means of a super call in derived class class Base2 { public int x = 10; } public class Derived2 extends Base2 { public int x = 20; } Derived2 d = new Derived2(); Base2 b = new Derived2(); System.out.println( "d.x=" + d.x); System.out.println( "((Base2)d).x=" + ((Base2)d).x); Hiding 20 10 System.out.println( "b.x=" + b.x); System.out.println( "((Derived2)b).x=" + ((Derived2)b).x); 27 Derived2 d-> x=10 x=20 10 20 Base2 b-> x=10 x=20 Hiding 06 Example: TestInstanceOf.java Instanceof p Person p = new Person(); System.out.println(p instanceof Person); System.out.println(p instanceof Student); true false Person p1 = new Student(); System.out.println(p1 instanceof Person); System.out.println(p1 instanceof Student); System.out.println(p1 instanceof Employee); Student TertiaryStudent Employee CollegeStudent true true false Person Student TertiaryStudent 28 Person p1 Employee CollegeStudent 06 Person Instanceof Student TertiaryStudent ts TertiaryStudent ts = new TertiaryStudent(); System.out.println(ts instanceof Student); Employee CollegeStudent true // System.out.println(ts instanceof CollegeStudent); // System.out.println(ts instanceof Employee); no instance of TertiaryStudent, or any of its possible subclasses could possibly be an instance of any subclass of CollegeStudent/Employee => Compile-time error Student s2 = new TertiaryStudent(); System.out.println(s2 instanceof TertiaryStudent); System.out.println(s2 instanceof CollegeStudent); //System.out.println(s2 instanceof Employee); true false Person Student Employee s2 TertiaryStudent CollegeStudent 29 06 Person Exercise: Student TertiaryStudent Employee CollegeStudent At compile-time, checking is carried out to determine whether the cast-type and the type of the existing reference variable are related through inheritance. At run time, a check is made to determine whether the object actually pointed to is compatible with the cast-type. Compiletime Runtime (TertiaryStudent) s1 OK OK (TertiaryStudent) s2 OK OK (TertiaryStudent) e1 ERROR (TertiaryStudent) s3 OK ERROR (TertiaryStudent) s4 OK ERROR (Students) S2 OK OK Student s1 = new TertiaryStudent(); TertiaryStudent s2 = new TertiaryStudent(); Employee e1 = new Employee(); Student s3 = new CollegeStudent(); Student s4 = new Student(); 30 06 Summary Object Conversion Make it possible to reference an object in a different way by assigning it to an object reference of a different type. It is handled automatically by the compiler. The object is NOT converted or changed in any way. Once instantiated, an object NEVER changes its type (a Cat will always be a Cat). The concept is similar to the "widening conversions" performed on primitive data types. Casting 31 Student s = new Student(); Person p = s; It is needed when the compiler doesn't recognize an automatic conversion. The concept is similar to the casting of primitive data types to perform a "narrowing conversion". Casting does not change the reference or the object being pointed to. It only changes the compiler’s treatment of the reference Casting is only legal between objects in the same inheritance hierarchy You can safely cast from an object to its superclass 06 Overriding, hiding, and overloading methods “An instance method in a subclass with the same signature (name, plus the number and the type of its parameters) and return type as an instance method in the superclass overrides the superclass's method.” “If a subclass defines a class method with the same signature as a class method in the superclass, the method in the subclass hides the one in the superclass. “The distinction between hiding and overriding has important implications. “Overloaded methods are differentiated by the number and the type of the arguments passed into the method.” 32 The version of the overridden method that gets invoked is the one in the subclass. The version of the hidden method that gets invoked depends on whether it is invoked from the superclass or the subclass.” “The compiler does not consider return type when differentiating methods, so you cannot declare two methods [in the same class] with the same signature even if they have a different return type. 06