程序代写代做代考 Java jvm compiler OOP++

OOP++

CSE 219
COMPUTER SCIENCE III

Object Oriented Programming

What is memory?

■ It’s basically a giant array of bytes!
■ How do we access this memory?

– in Java, we don’t!
– the JVM handles it for us
■ using memory addresses

■ The Java program uses object IDs
■ You must have seen these while debugging!

Stack Segment

Heap Segment

Global Segment

0xffffffff

0x00000000

Text Segment

Memory “segments”

■ Text segment
– stores program instructions

Stack Segment

Heap Segment

Global Segment

0xffffffff

0x00000000

Text Segment

Memory “segments”

■ Global segment
– data that can be reserved at compile time
– global data like static methods and variables

Stack Segment

Heap Segment

Global Segment

0xffffffff

0x00000000

Text Segment

Memory “segments”

■ (System) Stack segment
– temporary variables inside methods
– method arguments
– This data is removed from the stack once

the
method returns

■ Heap segment
– dynamic data
■ instantiation of new objects
■ This data is “persistent”:

– As long as there is a reference to an object in this
segment, it will not be removed.

Stack Segment

Heap Segment

Global Segment

0xffffffff

0x00000000

Text Segment

That’s all very fine, but …

■ The JVM handles all this automatically, so why should
the end programmer care?
– To understand the use (and abuse) of fundamental Java

concepts like
■ Generics and Type Abstraction
■ Actual vs Apparent types
■ Call-by-value
■ Static vs non-static

Designing a good framework

■ It’s complicated …
■ Extensive use of

– static and non-static members
– inheritance
– abstraction
■ abstraction is extremely important to make sure the framework is
extensible

– which is kind of the whole point of making a framework in the first place!

What is this “abstraction”?

■ Ignoring some low-level details, and
– Focusing on the big picture!
– Allows us to get a simpler, more streamlined solution to the

overall problem being addressed

■ Abstraction is
– the very first logical step in any design
– The main question is this:
■ “What part of the problem can be abstracted out ?”

– e.g., An add() method should not be designed for lists or sets separately, but
abstracted out to a higher-level, more general, solution!

Type Abstraction

■ Abstract from a data type to families of related types
– a many-to-one mapping
– e.g., public void equals(Object o)

■ How can we do this?
– Inheritance and Polymorphism

■ To understand type abstraction
– it helps to first know how objects are managed by Java

Types

■ Every variable has a type.
– The type defines how the variable is treated
– How much memory to allocate for it

■ Primitive data type
– int, short, long, byte, float, double, char, boolean

■ Class data type
– Any object of a class (i.e., not a primitive) is said to have the type

“class”.
– This is also called “Object type” or “Reference type”.

■ Generic type
– This is a generic class/interface that is parameterized over types
– The parameter can be replaced by a concrete “class type”

Strong Typing

■ Java is a strongly-typed language
– This term has slightly different definitions (depending on who

you’re asking)

– But in general, this means that the type of every variable is a
syntactic property
■ The compiler can determine the type without actually running the
program.

■ A variable can only be used in a way that respects the restrictions of
its type.

– e.g., it is impossible to perform a Double operation on an Integer
Hence the
need for
typecasting!

Runtime Safety

■ Runtime safety in Java is designed to ensure that no
variable can be interpreted as something it is not.
– e.g., for a String s, s.charAt(i) will throw an error if i is not in

the range 0, … s.length() – 1.
■ Some languages (e.g., C and C++) do not provide such safety nets!

■ Advantages of runtime safety and strong typing:
– Find errors early at compile time
– Improves “fool proof” programming
– Improves safety against malicious users (applets are generally

web-accessible)

A student is a person

■ Casting:
Student s = new Student();

Person p = (Person) s;

public class Person {
public String firstName;
public String lastName;
public String toString() {

return firstName + ” ” + lastName;
}

}
public class Student extends Person {

public double GPA;
public String toString() {

return “” + GPA;
}

}

Typecasting (again)

■ Remember Java’s type hierarchy?
– and in particular, how it restricts narrowing conversions?

■ Casting is a narrowing conversion.
– An object can always be cast to one of its ancestor types

Person p = new Person();

Student s = new Student();

p = new Student();

s = new Person();

p = (Person)new Student();

p = (Student)new Student();

s = (Person)new Person();

s = (Student)new Person();

Typecasting (again)

■ Remember Java’s type hierarchy?
– and in particular, how it restricts narrowing conversions?

■ Casting is a narrowing conversion.
– An object can always be cast to one of its ancestor types

Person p = new Person();

Student s = new Student();

p = new Student();

s = new Person();

p = (Person)new Student();

p = (Student)new Student();

s = (Person)new Person();

s = (Student)new Person();

Which lines would produce
compiler errors?

Which lines would produce
run-time errors?

Little boxes (of data)

■ We have spoken about any object being conceptualized
as a box before
– When we instantiate an object by calling new, the assigned

variable is a reference to that box
■ Actually, it is an ID

– Multiple references to the same box can exist
■ But after calling new, more variables cannot be added to the same box

Little boxes (of data)

■ We have spoken about any object being conceptualized
as a box before
– When we instantiate an object by calling new, the assigned

variable is a reference to that box
■ Actually, it is an ID

– Multiple references to the same box can exist
■ But after calling new, more variables cannot be added to the same box
Person p = new Student(); Student s = new Person();

firstName: null
lastName: null

firstName: null
lastName: null
GPA: 0.0

Java Collections

■ A very abstracted framework.
– Perhaps the most used abstracted code in Java

■ Examples:
– ArrayList implements List
■ i.e., an ArrayList can be passed to any method that takes a List.
■ similarly, so can a LinkedList.

– Abstracted methods for comparison
■ Extremely useful for sorting!
■ Comparable and Comparator

Sortable students

■ A very practical abstraction
– Collections.sort

– overloaded method
■ public static > void sort(List list)

■ public static void sort(List list, Comparator c)

■ Then we will look at (again!)
– Comparable versus Comparator

Using the natural ordering

■ The comparable interface imposes a “natural” ordering
– a natural order is a total order

■ So what is a “total order” ?
– a binary relation R on a set ( let’s call it S )
■ transitive

– ∀”, $, % ∈ ‘ ∶ “)$ ∧ $)% ⇒ “)%. e.g., >, ≥, = are transitive (on the set of numbers)
■ anti-symmetric

– ∀”, $ ∈ ‘ ∶ “)$ ∧ $)” ⇒ ” = $. e.g., ≥ is an anti-symmetric relation
■ total

– ∀”, $ ∈ ‘ ∶ “)$ ∨ $)” e.g., ≥ is a total ordering

Using the natural ordering

public class Student extends Person implements Comparable {

public double GPA;

public String toString() { return “” + GPA; }

public int compareTo(Student s) {

if (GPA > s.GPA) return 1;

else if (GPA < s.GPA) return -1; else return 0; } } Natural Ordering and Sorting public static void main(String[] args) { ArrayList students = new ArrayList<>();

students.add(new Student(“Bob”, “Marley”, 3.9));

students.add(new Student(“Joe”, “Satriani”, 2.5));

// this is our code. we know what’s happening here

System.out.println(students.get(0).compareTo(students.get(1)));

// but this depends on the list implementation

System.out.println(Collections.sort(students));

This is the 1st of the
two overloaded
Collections.sort()
methods.

Extending the natural order ?

■ Suppose we have
– public class Person implements Comparable

■ Then, can we have this
– public class Student extends Person implements

Comparable

■ No L
– ‘java.lang.Comparable’ cannot be inherited with different type

arguments: ‘comparisons.Person’ and ‘comparisons.Student’

To compare or not to compare …

■ Suppose that were allowed
– public class Person implements Comparable

– public class Student extends Person implements

Comparable

■ What do the corresponding compareTo() methods look like?
@Override
public int compareTo(Person that) {

return this.toString().compareTo(that.toString());
}

@Override
public int compareTo(Student that) {

// the GPA comparison code we saw earlier
}

To compare or not to compare …

■ Then, effectively, we have one class implementing two
comparable interfaces
– one by itself
– one inherited from its superclass

■ If these two implementations have different parameter
types (e.g., Student and Person)
– what do you think happens after type erasure ?

To compare or not to compare …

■ We could override compareTo() in the extended class

■ Defeats the whole idea of abstraction !!
■ It’s much better to simply fall back on the Comparator

@Override
public int compareTo(Person p) {

if (p instanceof Student) {
Student that = (Student) p;
if (this.gpa > that.gpa) return 1;
if (this.gpa < that.gpa) return -1; return 0; } else throw new IllegalArgumentException("Impostor!"); } Comparator public class StudentComparator implements Comparator {

@Override
public int compare(Student s1, Student s2) {

if (s1.GPA > s2.GPA)

return -1;
else if (s1.GPA < s2.GPA) return -1; else return 0; } } Comparator public class StudentComparator implements Comparator {

@Override
public int compare(Student s1, Student s2) {

if (s1.GPA > s2.GPA)

return -1;
else if (s1.GPA < s2.GPA) return -1; else return 0; } } This gets used by the 2nd of the two overloaded Collections.sort() methods. JAVA: apparent vs actual types ■ Apparent type – what the variable declaration said – Person p; // apparent type is Person – this is what the compiler cares about – can tell simply by looking at the declaration ■ Actual type – what it really is – Person p = new Student(); // actual type is Student – this is what the JVM cares about – can tell only by tracing through the code at runtime JAVA: apparent vs actual types ■ Apparent type – determines what methods can be invoked on an object ■ what if the method is overridden again and again ? ■ Actual type – determines which implementation of the method is called ■ e.g., if the apparent type is Person but the actual type is Student, which implementation of the toString() method will be invoked ? – the JVM knows the actual type ■ and calls the implementation in that class Pass-By-Value (a.k.a. call-by-value) ■ The actual argument is fully evaluated ■ The resulting value is copied into a location – This is the location used to hold the argument’s value during method execution ■ typically a chunk of memory on the runtime stack for the application – in JAVA (some other programming languages do things differently) ■ JAVA is strictly pass-by-value! – stay away from people who claim otherwise Pass-By-Value ■ Often, you may hear statements like – “In Java, objects are passed by reference, and primitives are passed by value.” ■ This is a half-truth! ■ Primitives are, of course, passed by value ■ But objects are not passed by reference! – references to objects are passed by value ■ This may look like we are splitting hairs – but it’s a very important hair Pass-By-Value: an example public void foo(Dog d) { d = new Dog("Fifi"); // bow wow } public static void main(string[] args) { Dog aDog = new Dog("Max"); // woof woof foo(aDog); // aDog is still Max } Pass-By-Value: an example public void foo(Dog d) { d = new Dog("Fifi"); // bow wow } public static void main(string[] args) { Dog aDog = new Dog("Max"); // woof woof foo(aDog); // aDog is still Max } The value of aDog in main() is not overwritten in foo() How is my dog still Max? ■ Primitives are passed by value ■ Object references are passed by value – An object itself is never passed to a method – The object is always in the heap ■ Only a reference to the object is passed to a method ■ References – this is Java nomenclature – everywhere else in the world of programming languages, they’re called pointers, and Java couldn’t avoid it entirely … ■ NullPointerException Think of balloons instead of dogs ■ Imagine a balloon ■ Calling a function is like tying a 2nd string to the balloon and handing the line to the function parameter ■ “= new Balloon()” will cut that string and create a new balloon – but this has no effect on the original balloon! ■ Java is pass by value, but the value passed is not deep, it is at the highest level, i.e. a primitive or a pointer. ■ Don't confuse that with a deep pass-by-value where the object is entirely cloned and passed. Interfaces ■ “Contracts” of sorts – define how communication happens (through methods) – without getting into the implementation details ■ In JAVA, an interface – is a reference type (just like classes) – can only contain – constants – method signatures – default methods – static methods – nested types Interfaces as Types ■ An interface is a reference data type – You can use an interface name anywhere you can use any other data type name – A variable v whose (apparent) type is an interface ■ any assignment to v must be an instance of a class that implements that interface Designing an interface ■ You have an interface with two method signatures – doThis(int x, String y) – doThat(String y) ■ But in future, you realize that it’d be nice to have another functionality – so you want to add a 3rd signature doMore(String y, String z) ■ Then, all classes implementing this interface will break! ■ Anticipating all future uses is difficult – So, interfaces can also be extended J Abstract classes and methods ■ Abstract classes – declared using the keyword abstract ■ public abstract class Klass { ... } – may or may not have abstract methods ■ abstract void m(); – if a class contains an abstract method ■ it must be declared abstract – cannot be instantiated (just like interfaces) – but they can be extended by subclasses ■ Highly recommended – http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html