Java - Implementing sorting algorithms the 'right' way - java

I'm currently playing with implementing various sorting algorithms in Java, mostly for fun, but I'm struggling with how to do it 'right'. That is, I want the user to be able to call the sorting algorithm of choice on anything that is comparable - ints, longs, Strings, booleans (actually, are these comparable in Java?), their own classes; whatever. The question is how to do this.
I was thinking of using a class to represent the sorting algorithm, and therefore store the things to be sorted inside using a generic list or whatever (List<E>). This would also allow me to use multiple constructors and thus allow the user to pass in the data in various forms - Lists, Arrays, whatever. Is this the correct way to do it? My current problem is that I don't wish for the user to have to create a class when they want to sort something, I'd rather it was able to be called much like System.out.println or the like.
// Example:
int[] myInts = {5,4,3,2,1};
// This is what I do *not* want.
InsertionSort mySort = new InsertionSort();
int[] sortedInts = mySort.sort(myInts);
// This is more like what I want.
int[] sortedInts = Sorting.insertionSort(myInts);
I apologise with what may seem like a basic question, but I am just learning my way with programming languages. Which is a bit ridicolous for a 2nd year Computing student working at a software company for his summer job, but you'd be surprised at how little programming knowledge is required for most of my work... it's usually more design knowledge.
EDIT:
For clarity, my three main question are:
Is it better to have the user create a class to do the sorting, or to have a static method in a class the user imports?
Is it possible to deal with both primitive data types and generic objects easily? Since I want to be able to handle any generic object that implements comparable (or likewise), this then causes problems with primitives (as they don't implement anything ;) ).
What is the best way to handle generic input - what should I check for before I try to sort them (implementing Comparable, for example)?

You could take as example the way Collections provides the binarySearch operation ... And indeed, the
int[] sortedInts = Sorting.insertionSort(myInts);
is more java-way, even if I would personnally prefer
public class Sorting {
public static <DataType extends Comparable> Iterable<DataType> insertionSort(Iterable<DataType> data);
}
<DataType> ensure output data is of the same type than input
Iterable<DataType> data input data is an iterable, to ensure maximum compatibility. Obviously, using a List would be by far simple, as it allows internal item reordering. Howeve"r, using an iterable ensure the implementor of this method will have to re-create the list in order to modify it, guaranteeing that the input list is left unchanged, and that the output list is another one.
Since I just saw you edit your question, let me reply to it point by point (and consider chosing an answer after that, as it is easier to add new questions than to edit existing ones endlessly - unless you make your question a community wiki, like I do of this reply)
Is it better to have the user create a class to do the sorting, or to have a static method in a class the user imports?
To my mind, using a static method in this case is preferable, as you here have to manipulate objects you didn't create, in a quite "basic" fashion.
Is it possible to deal with both primitive data types and generic objects easily? Since I want to be able to handle any generic object that implements Comparable (or likewise), this then causes problems with primitives (as they don't implement anything ;) ).
Have you heard about autoboxing ? It's a feature of Java 5 which makes primary types "equivalents" of objects. That's to say int are automatically converted into Integer, which, as you know, implement Comparable.
What is the best way to handle generic input - what should I check for before I try to sort them (implementing Comparable, for example)?
Notice that, due to my method declaration (the ), checking that input data implements Comparable is not done by you, but by the Jav compiler, allowing your IDE to show you mistakes.

I think you answered your own question? If you want to expose a static method instead of making the user create and object and call an instance method, then just do that. Sorting.insertionSort() looks fine to me.
Internally that can dispatch to whatever you like. Inside, if you want to implement this with classes and polymorphism and whatnot, go ahead. It does seem like a bit overkill though. I am not sure inheritance and polymorphism help a lot here.

The normal way of implementing a sorting algorithm would be to implement a static method, e.g. take a look at the source code for Arrays.sort(). You can overload this method with diferent implementations for different parameter types (e.g. objects that implement comparable vs. provide your own comparator vs. primitive arrays etc.)
Here's one I wrote earlier:
public static <T> void swap(T[] a, int x, int y) {
T t=a[x];
a[x]=a[y];
a[y]=t;
}
public static <T extends Comparable<? super T>> void mergeInOrder(T[] src, T[] dst, int p1, int p2, int p3, int p4) {
if (src[p2].compareTo(src[p3])<=0) return; // already sorted!
// cut away ends
while (src[p1].compareTo(src[p3])<=0) p1++;
while (src[p2].compareTo(src[p4])<=0) p4--;
int i1=p1;
int i3=p3;
int di=p1;
while(di<p4) {
if (src[i1].compareTo(src[i3])<=0) {
dst[di++]=src[i1++];
} else {
dst[di++]=src[i3++];
if (i3>p4) {
System.arraycopy(src,i1,dst,di,p2-i1+1);
break;
}
}
}
System.arraycopy(dst, p1, src, p1, (p4-p1)+1);
}
public static <T extends Comparable<? super T>> void mergeSort(T[] src, T[] dst, int start, int end) {
if (start+1>=end) {
if (start>=end) return;
if (src[start].compareTo(src[end])>0) {
swap(src,start,end);
}
return;
}
int middle=(start+end)/2;
mergeSort(src,dst,start, middle);
mergeSort(src,dst,middle+1, end);
mergeInOrder(src,dst,start,middle,middle+1,end);
}
private static ThreadLocal<Comparable<?>[]> mergeSortTemp=new ThreadLocal<Comparable<?>[]>();
#SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> void mergeSort(T[] src) {
int length=src.length;
Comparable<?>[] temp=mergeSortTemp.get();
if ((temp==null)||(temp.length<length)) {
temp=new Comparable[length*3/2];
mergeSortTemp.set(temp);
}
mergeSort(src,(T[])temp,0,length-1);
}
However, I can think of two good reasons to implement a sorting algorithm as a class where you generate your own instance:
It lets you polymorphically pass around instances of sorting algorithms - this could be useful if e.g. you were creating a collection of sorting algorithms and wanted to run lots of benchmarks on them for example.
You can have private state in the sorter instance - this is useful for some sorting algorithms, e.g. having some pre-allocated arrays for temporary storage, and it makes sense to put it in a class instance if you want to be able to simultaneously use different sort instances from multiple threads - a static method implementation would need some form of synchronisation (e.g. see the use of the ThreadLocal in the code above).

I'm not sure if this is what you are struggling with ... but it is next to impossible to implement an algorithm that works both for reference types and (real) primitive types. The reason is the Java type system does not have a notional universal type that has the primitive types and Object as subtypes.
The normal workaround for this is to wrap the primitive types using their corresponding wrapper classes; e.g. Integer for int, Boolean for bool and so on. This allows you to implement (for example) a sorting algorithms that for for any Collection<T> or any <T>[].
This approach has performance / memory usage issues when applied to large arrays of (say) integers. Either you wear the performance hit, or you implement the algorithm and its supporting classes separately for each primitive type.
(I said next to impossible, because it is possible to abstract the comparison of a pair of array elements and swapping of a pair of array elements in a way that doesn't expose the actual element type in the interface; e.g.
public interface ArraySortAdapter {
public abstract int compareElements(Object array, int pos1, int pos2);
public abstract void swapElements(Object array, int pos1, int pos2);
}
and provide different implementations for different array types; e.g.
public class IntArraySortAdapter implements ArraySortAdapter {
public int compareElements(Object array, int pos1, int pos2) {
int[] intArray = (int[]) array;
if (intArray[pos1] < intArray[pos2]) {
return -1;
} else if (intArray[pos1] > intArray[pos2]) {
return +1;
} else {
return 0;
}
}
...
}
However, this is cumbersome and inefficient, to say the least ...)

Related

Proper use of generics in abstract java class?

EDIT: This question is not well worded, and the provided answer is correct in a literal sense but did not teach me how to attain what I needed. If you are struggling with the same problem, this is what finally helped me: How to enforce child class behavior/methods when the return types of these methods depends on the child class?
I am trying to implement a basic matrix class from a boilerplate abstract class I wrote. There will be several implementations of this abstract class, each one using a different math library, which I will then test for speed.
Each implementation will hold its data in that library's native matrix data structure. I think this is a use case for generics. At this point I think I've read too many tutorials and watched too many videos, as I just can't seem to figure out all the right places to put the T Notation to make this work correctly.
So my question is twofold:
Have I misused or missed the point of generics?
If not, what is the correct syntax for their use?
I've read the docs plus about three different tutorials and still can't understand.
Here is what I've tried:
public abstract class BaseMatrix<T> {
protected int[] shape;
protected int nrows;
protected int ncols;
protected T data; // <--- Here is the generic data --->
public BaseMatrix(int rows, int cols){
this.nrows = rows;
this.ncols = cols;
this.shape = new int[]{nrows, ncols};
}
public abstract BaseMatrix mmul(BaseMatrix other);
And here is my implementation:
public class ND4JDenseMatrix extends BaseMatrix{
// private INDArray data;
public ND4JDenseMatrix(int rows, int cols) {
super(rows, cols);
this.data = Nd4j.zeros(this.shape); <--- Here is the non-generic data --->
}
#Override
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
ND4JDenseMatrix result = new ND4JDenseMatrix(nrows, ncols);
result.data = data.mmul(other.data);
return result;
}
The error is: Method does not override method from its superclass.
hold its data in that library's native matrix data structure. I think this is a use case for generics.
Generics serves to link things. You declared the type variable with <T>, and you've used it in, as far as your paste goes, exactly one place (a field, of type T). That's a red flag; generally, given that it links things, if you use it in only one place that's usually a bad sign.
Here's what I mean: Imagine you want to write a method that says: This method takes 2 parameters and returns something. This code doesn't particularly care what you toss in here, but, the parameters must be the same type and I return something of that type too. You want to link the type of the parameter, the type of the other parameter, and the return type together.
That is what generics is for.
It may apply here, if we twist our minds a bit: You want to link the type of the data field to a notion that some specific implementation of BaseMatrix can only operate on some specific type, e.g. ND4JMatrix.
However, mostly, no, this doesn't strike me as proper use of generics. You can avoid it altogether quite easily: Just.. stop having that private T data; field. What good is it doing you here? You have no idea what type that is, you don't even know if it is serializable. You know nothing about it, and the compiler confirms this: There is absolutely not one iota you can do with that object, except things you can do to all objects which are generally quite uninteresting. You can call .toString() on it, synchronize on it, maybe invoke .hashCode(), that's about it.
Why not just ditch that field? The implementation can make the field, no need for it to be in base!
public class ND4JDense extends BaseMatrix {
private ND4JMatrix data; // why not like this?
}
(This code assumes 'ND4JMatrix' is the proper data type you desire here, a thing that can is the internal representation for the data in the ND4J impl).
However, if you must, yeah, you can use generics here. You've type-varred BaseMatrix, and that means all usages of BaseMatrix must be parameterized. That's the part you messed up in your code. If we go with your plan of a type-parameterized BaseMatrix class and a field of type T, the right code is:
public class ND4JDense extends BaseMatrix<ND4JMatrix> {
...
}
I wouldn't, however, do it this way (I'd go with having the impl have the field, much simpler, no need to bother anybody with the generics). Unless, of course, you DO have an actual need for that field and it IS part of BaseMatrix's API. For example, if you want this:
public class BaseMatrix<T> {
public T getData() { return data; }
}
then it starts to make more sense. With that, you can write the following and it'll all compile and work great:
public class ND4JDense extends BaseMatrix<ND4JMatrix> {
...
// no need to write a getData method here at all!
...
}
ND4JDense dense = new ND4JDense();
ND4JMatrix matrix = dense.getData();
But, clearly, this makes no sense if you intend for the ND4JMatrix to remain an implementation detail that users of the BaseMatrix API should probably not be touching.
EDIT: You changed the question on me, later. Now you want the mmul method to take 'self' as argument, effectively: You want the same type to be passed in.
You can sort of do that but it is a little tricky. You need the self-ref generics hack. It looks like this:
public class BaseMatrix<T extends BaseMatrix<T>> {
public abstract T mmul(T other);
}
In practice the only valid value for T is your own class, or at least, that is the intent. This works fine:
public class ND4JDenseMatrix extends BaseMatrix<ND4JDenseMatrix> {
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
.. impl here ..
}
}
As far as I see, you have two issues in your code:
You're not actually overriding the method of the superclass. What you have created is an overload of method mmul. To correctly override the method, the method signature must match, in particular the input parameter must be the same. It's ok to have a subtype of the return type, as Java support covariant. If you instead put one of its subclass, that is overloading. Hope you get the difference. So the correct signature can be the following:
public BaseMatrix mmul(BaseMatrix other) {
...
}
You have not specified the type T, so the compiler cannot know that by assumption is a subtype of BaseMatrix. it can be any type, even Object for example, so you are going to get "method not found" compilation error.

Generics and interface // do I have to use them together?

I'm learning Java but I believe that this question is not language-specific. Sorry if someone has already asked the question, I'm not sure how to phrase this in a search query.
Shortly after implementing a few generic methods for myself, I came to realize that: Since Generics allow you to use parameters of more types, some of the arguments that the user puts in might not have the functionality that you expect. A "hack" that I came up with is to restrict the parameter input type using an interface as an Upper Bound. For popular functionalities like compareTo(), this is fine as the interface Comparable is popular enough, but I find it awkward that I have to write a custom interface just to get my generics to work.
Here's some code to help make sense of my nonsense. Consider the following non-working code that attempts to count unique elements in a collection of generic datatype:
public static <T> int countUnique(Collection<T> c) {
int count = 0;
for(T t : c) {
count += (t.isUnique()) ? (1) : (0);
}
return count;
}
An obvious problem arises when the compiler complains that the objects t do not have (or rather, the compiler cannot determine that they have) the method isUnique(). My solution:
public interface unique {
public boolean isUnique();
}
public static <T extends unique> int countUnique(Collection<T> c) {
int count = 0;
for(T t : c) {
count += (t.isUnique()) ? (1) : (0);
}
return count;
}
Question is: Do I have to do this every time? Isn't it clunky? Is there a standard practice that I should instead be adopting?
This is the main principle of OOP. You're working with objects and objects have behaviors (methods).
Every method knows what objects it is working with. For example, your method compares 2 numbers. If you pass 1 number and 1 Array of Strings it won't be able to compare them.
You don't have to use interface as upperbound in your example.It can be your class and in case you have 2 classes that have similar behavior then you create an interface and change your method above to use that interface.
Also, by Java Code Conventions interface name should start from capital letter.

Instantiate an object that takes a generic collection

I am learning Java generics and I am trying to adapt some code I developed as an exercise.
In particular, I developed an ArrayVisualizer class that uses Sedgewick's StdDraw library to visualize and animate the behaviour of a dynamic array. I have my own dynamic array class which supports generics, and I am trying to extend the usage of ArrayVisualizer to anything that is akin to this array.
In short, my question is: how can you deal with generic types containing other generic types?
Here is my thought process:
I started by making this Interface:
public interface IterableCollection<Item> {
void add(Item i);
Item get(int index) throws IndexOutOfBoundsException; // These can be slow for LinkedList implementations
void set(int index, Item value) throws IndexOutOfBoundsException;
int capacity();
int size(); // Capacity and size can be the same for LinkedList implementations
}
Then, I would like my ArrayVisualizer class to take as parameters any class that implements this Interface. After some googling, I found that you can't write
public class ArrayVisualizer<T implements IterableCollection<?> >
but you have to use extends.
However, even if I write that I can't use the T class inside my functions.
For example, I have a compiler error if I try to generalize this function:
public static void draw(T<String> vector) throws Exception
It is like I have to specify that T is also generic, but I can't find a way to declare it. I have tried the following, and none works:
public class ArrayVisualizer<T<?> implements IterableCollection<?> >
public class ArrayVisualizer<T<S> implements IterableCollection<S> >
RESOURCES: I have uploaded the working non-generic version of my code as a reference.
DynamicArray.java
ArrayVisualizer.java (this takes some spaced strings as input)
InteractiveArrayVisualizer.java (this one doesn't allow to choose the values of the cells but you can fill them by clicking on the next empty spot and you can empty them by clicking on the last open cell. This is meant to use a debug helper for the resize problem of the dynamic array).
Your ArrayVisualizer class must specify both the collection type, and the element type. You cannot quantify over T<String> like that in Java. (Other languages can do it, but not Java.)
So, something like....
class ArrayVisualizer<E, T extends IterableCollection<E>> {
public void draw(T vector) { ... }
}
(although if I were you, I would try to use the pre-built Iterable or Collection interface rather than my own IterableCollection interface...)

Java arrays and foreach iteration implementation

Is there some interface that will allow for iteraction of arrays and java.util.Lists?
Seeing as how the for-each loop can iterate both it seems to me there must be some sort of base 'iterable' that is being traversed in both cases.
So, can i setup a method parameter that accepts either Foo[], or List?
We have lots of old code (which we won't be updating), that calls a few low level methods (which i'd like to update) that are expecting arrays.
Our new code is converting from Lists (specifically ArrayLists most of the time) to arrays using List's toArray method, and i'd like to be able to skip this step.
I've seen this post which shows the implementation, but I'm not sure how it might help.
Can this be done?
No, the language specification explicitly calls out arrays separately. Arrays don't implement Iterable<T>, which is the "normal" interface used by the enhanced for loop other than for arrays. From section 14.14.2 of the JLS:
The enhanced for statement has the form:
EnhancedForStatement:
for ( VariableModifiers Type Identifier: Expression) Statement
The Expression must either have type Iterable or else it must be of an array type (§10.1), or a compile-time error occurs.
The two cases are then handled separately.
Converting from arrays to lists is easy of course - but it sounds like you need to do this the other way round. There's really no "pleasant" way of doing this - and creating the array requires copying everything, of course.
How much work would it be to convert at least the most heavily used bits of the API to use lists?
You can write method overloads of course, e.g.
public void foo(String[] array)
{
foo(Arrays.asList(array));
}
public void foo(List<String> list)
{
// Use the list
}
... but doing that for your old code will still involve work, as the real implementation is in terms of the list, not the array.
Java could have made Foo[] a subtype of Iterable<Foo>; unfortunately that won't work on primitive arrays because Java doesn't support primitive type arguments, so we don't have this nicety.
I think arrays are just special cased in the for loop's implementation.
One thing you can do is overload your methods:
public void foo(MyClass[] stuff) {
foo(Arrays.asList(stuff));
}
public void foo(Collection<MyClass> stuff) {
// stuff
}
Or the other way around:
public void foo(MyClass[] stuff) {
// stuff
}
public void foo(Collection<MyClass> stuff) {
foo(stuff.toArray(new MyClass[stuff.size()]));
}
There is not such a common interface, an Array does not implement Iterable.
What you can do is to overload you method:
public void mymethod(String ... strings) {
mymethod(Arrays.asList(strings));
}
public void mymethod(List<String> strings) {
// do what you need
}

Meaning of Types, Class, Interface?

Find many authors interchangably use the term Type and Class. Certain textbooks covering object based model covers the term Interface also.
Could someone please explain these in simple terms based on Object Oriented Programming in general and C++/Java/object-oriented-database in particular.
A type is a classification of a piece of data telling you what its permissible values and permissible operations are. (Almost?) all programming languages have types, although the typing discipline varies considerably from one language to another.
A class is a particular kind of type in OOP languages which is defined with a specific syntax in the language itself (as opposed to, say, so-called "native types" like Java's int or float or the like which are defined by the language proper). A class is typically defined in terms of a memory layout and encoding of data (so-called member variables) and the functions that work on them (so-called member functions or methods).
An interface* is a specification of what operations a type must implement to be considered part of a given set of similar types but which does not specify permissible values, memory layouts, etc.
This is a very, very, very brief overview that is kind of the simplified "average form" of several languages' approach to these. It ignores a few edge cases and things like C++'s ability to make things that are part-way between an interface and a class. It also ignores what classes are in functional languages like Haskell because damaging your brain farther is not the goal here. ;)
edited to add some examples
Here are some Java-like declarations to help cement the concepts.
int myVariable1;
This variable—myVariable1—is a native (or primitive) type consisting of a 32-bit signed integer value encoded in 2s-complement notation. It has a known range (of approximately -2 billion to +2 billion) and a known set of operations (multiplication, addition, division, modulus, subtraction, various conversions, etc.) available to it.
class MyClass
{
int myMemberVariable;
int myOtherMemberVariable;
int myMethod(int p) { myMemberVariable += p; myOtherMemberVariable = p; }
}
MyClass myVariable2 = new MyClass();
Here myVariable2 is a type defined by the class MyClass. MyClass defines the memory layout (which in this case consists of two 32-bit signed integers in 2s-complement notation) as well as the single operation myMethod() which adds its argument to myMemberVariable and sets myOtherMemberVariable to that argument.
interface MyInterface
{
int myInterfaceMethod(int p, int q);
}
Here MyInterface only declares a set of operations (consisting in this case of the single function myInterfaceMethod()) without any member variables and without any implementation. It only tells you that any class that implements this interface is guaranteed to have a method with that specific signature of name + return value + arguments. To use it you have to make a class that implements the interface.
class MyOtherClass implements MyInterface
{
int myMember1;
int myMember2;
int myMember3;
int myInterfaceMethod(int p, int q) { myMember1 = p; myMember2 = q; myMember3 = p - q; }
int myNonInterfaceMethod() { return myMember1; }
}
MyOtherClass myVariable3 = new MyOtherClass();
Now myVariable3 is defined as a type with a memory layout consisting of three signed 32-bit integers and two operations. One of those operations is one it must implement because of the whole implements MyInterface portion. This way anything that's expecting the (abstract) MyInterface type can use the (concrete) MyOtherClass type since the operation is guaranteed to be there. The other method—myNonInterfaceMethod()—does not come from MyInterface so something that is expecting only a MyInterface can't use it because it can't know it exists.
further edited to add some real-world stuff by request
If you've ever used an integer value, a floating point value, a string or anything like this in a program you've used types. Types are arguably the stuff of computing and everything we do is manipulation of values of given types. I'll focus, therefore, on the OOP-specific notions of classes and interfaces.
Any time you have data and operations on that data you have the potential for a class. Take, for example, a bank account. A bank account will have, among other things, an account number, a current balance, a transaction limit, etc. A class representing this (badly and shown only to explain concepts) might look like this:
class BankAccount
{
String accountNumber;
float balance; /* DO NOT USE FLOATING POINT IN REAL FINANCIAL CODE! */
int transaction_limit;
float transaction(float change) {
balance += change > transaction_limit ? transaction_limit : change;
return balance;
}
}
Now you can make a variable of this type and know that it will carry around an account number (which is itself a String type), a balance (which is itself a float type -- but DON'T USE FLOATING POINT IN REAL WORLD FINANCIAL CODE!) and a transaction limit (which is itself an int type). You also know you can perform a transaction (creatively called transaction) which will check the change against the transaction limit and modify the balance. (A real class for this would contain lots more and would contain a lot of obfuscatory protection stuff that I've removed for pedagogical purposes.)
Now let's say you're in a more sophisticated financial environment in which there are several kinds of transactions, not just bank accounts. Let's say further you've got some code that will process transactions that doesn't care what the specifics of the underlying types are. An offline batch processor of transactions, say, that covers bank accounts, accounts receivables accounts, etc. Rather than making it know about every kind of transaction in the book, we can do this instead:
interface Transactable
{
float transaction(float change);
}
class BankAccount implements Transactable
{
/* interior is identical */
}
class ReceivablesAccount implements Transactable
{
float balance;
float transaction(float change) { balance += change; }
}
Now anything that knows about Transactable types can use both your BankAccount's instances as well as your ReceivablesAccount's instances. They don't have to know that bank accounts have transaction limits while receivables accounts don't. They don't have to know anything about the internal representation of the data. They don't have to know the special cases of anything. They just have to know about one function by name (transaction()) and that's it. (If you want more concrete real-world usage of this, look at how the collection classes, not to mention the "for in" loop, use the Iterable interface in Java.)
In O.O.P parlance is very common to use the Terms Type and Class interchangeably, especially when talking about some languages like java and/or C++.
Generally speaking, when you define a Class you're actually defining a Type template, from which objects of the Type you're defining will be created, and/or instantiated.
The concept of interface is a little bit more complicated, when you define an interface you're basically specifying a particular way to deal with any Type of object that does use of it. That is, your object must come from a class that implements that interface. An interface is a way of enhancing your Class/Type by specifying additional behavior not contained in the original Class/Type specification.
For many practical purposes you can treat an Object thorough it's interface as if it were of the interface type, that's probably why the term interface is used interchangeably with the term type.
See the theory behind Abstract Data Types for further insight.
Personally, I think it's easier to understand if you describe it in concrete terms. For example, let's say we want to build a program to track inventory of things in a kitchen.
Most languages only know about very simple, primitive "Types" of things like integers, characters, and bytes. We could totally use these primitive Types to describe the types of things in a kitchen. For example, you could construct an array of an array of characters where each index in the array represents an attribute of something. Like, maybe, index 0 represents the "type" of thing you're trying to describe. But, of course, this technique would get very complicated very quickly.
So, using Object Oriented techniques, we can easily define new Types by combining primitive Types. The way that you do that is by creating a Class definition. Think of a Class as a blueprint for a new Type.
In the kitchen example, we have the concept of "Food" Type, "Appliance" Type, and "Furniture" Type. In order to use these new types in the program, we'd need to create a class definition for each of these:
public class Food {...}
public class Appliance {...}
public class Furniture {...}
An Interface describes how we can interact with something. For example, we want to create an inventory of things in our kitchen. We will want to be able to "Add" to our inventory, "Remove" things from our inventory, and maybe "Iterate" over our inventory. The actions "Add", "Remove" and "Iterate" apply to pretty much any list of anything (not just our inventory). Java provides an interface named "List" for this purpose. By creating an inventory object with the very popular and common List "Interface", we get all the actions for free and other programmers can look at our program and know exactly how to interact with the "Inventory" object:
...
java.util.List inventory = new ArrayList();
...
//later in our program, we can interact with inventory
// with any of methods on the list interface (because ArrayList "implements" List)
inventory.add(new Furniture("chair"));
inventory.add(new Appliance("refrigerator"));
inventory.add(new Food("ice cream"));
...
So, in the example above, inventory is variable that contains an instance of type ArrayList. Since the ArrayList Class definition implements the "List" interface, all instances of Type ArrayList must obey the contract defined in the the "List" interface. In other words, we could have just as easily created inventory as a LinkedList (instead of an ArrayList) like this:
java.util.List inventory = new LinkedList();
Remember to think of an interface as a contract that exposes a specific set of actions to be preformed. Because LinkedList and ArrayList both implement the "List" interface, they are both contractually obligated to implement all the methods in the "List" interface.
The great thing about this is that any code that is interested in using our "inventory" variable doesn't give a crap about how the "add", or "remove", or "iterator" actions are implemented. All they care is that the variable "inventory" obeys the "List" interface.
In other words, LinkedList implements the "add" method slightly different than ArrayList. But that doesn't matter to any code that wants to use our "inventory" variable.
If some math whiz comes up with a revolutionary way to store lists. Maybe they figure out how to store lists on the moon rather than inside computer memory and that turns out to be 10x faster than ArrayList. Then all we'd need to do is this:
java.util.List inventory = new CrazyMoonList();
All the other code that uses inventory can stay exactly the same because CrazyMoonList is guaranteed to provide "add", "remove", etc.
Hope this helps clarify the concepts!
A class is a template for an object, a user-defined datatype that contains variables, properties, and methods.
//defines a simple class describing all types of fruit
public class Fruit {
//insert fields here...
Fruit(){//constructor method
//insert constructor code here...
}
//insert class methods here....
}
When we instantiate this class to be an object, we need to let the compiler know what type of object it is going to be. In this case our object is going to be of type Fruit.
//The initialisation might look something like this.
Fruit myFruit = new Fruit();
The previous line of code tells the compiler to construct a new object of type Fruit.
So in simple terms "class" defines an objects characteristics (its data), where as "type" is refers to what type of object we are looking at when it has been instantiated, whether it be a Fruit, Car, or Desk!
This concept can be expanded upon by reading further into the topics of Inheritance and Polymorphism.
I hope this is of help.

Categories