0% found this document useful (0 votes)
37 views92 pages

Java Unit-3 Student

The document discusses multithreading, I/O, and generics in Java programming. It covers topics like creating threads, thread priorities, synchronization, inter-thread communication, I/O basics, reading and writing files and console, and generics concepts.

Uploaded by

samsundar793
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views92 pages

Java Unit-3 Student

The document discusses multithreading, I/O, and generics in Java programming. It covers topics like creating threads, thread priorities, synchronization, inter-thread communication, I/O basics, reading and writing files and console, and generics concepts.

Uploaded by

samsundar793
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 92

22CS202

JAVA PROGRAMMING

UNIT III

MULTITHREADING, I/O AND GENERIC PROGRAMMING


SYLLABUS
Multithreaded Programming: Creating a Thread, Thread Priorities,
Synchronization, Interthread Communication
I/O: I/O Basics, Reading Console Input, Writing Console Output,
Reading and Writing Files
Generics: Introduction, Generic class, Bounded Types, Generic
Methods, Generic Interfaces, Generic Restrictions.
THREAD

Thread

• A thread is referred as a light weight smallest part of a process.

• Threads are independent because all the threads follow a separate path
of execution within the program.

• Each thread has its own program counter, stack and local variables.

• It uses a shared memory area, files and per-process state.


Multithreading

• The process of executing multiple threads simultaneously is known


as multithreading.
• Multithreading is a programming concept where a program (process)
is divided into two or more subprograms (process), which can be
implemented at the same time in parallel.
• A multithreaded program contains two or more parts that can run
concurrently and each part can perform different task at the same time
making optimal use of the available resources.
• Each part of such a program is called a thread, and each thread defines
a separate path of execution.
Advantages of Java Multithreading

• It doesn't block the user because threads are independent and


multiple operations can be performed at the same time.
• It can perform many operations together, hence saves time.

• Threads are independent, so it doesn't affect other threads if an


exception occurs in one thread.
Multitasking

•Multitasking is a process of executing multiple tasks simultaneously.


Multitasking is when multiple processes share common processing
resources such as a CPU.
•Multitasking can be achieved in two ways:
 Process-based Multitasking (Multiprocessing)
 Thread-based Multitasking (Multithreading)
Process-based multi-tasking (Multiprocessing)

•Executing various jobs or process together where each process is a separate

independent operation is called process-based multi-tasking.

•Each process has a separate address in memory and switching from one process

to another requires some time for saving and loading registers and updating lists.

•A process is heavy weight and cost of communication between the process is high.
Thread-based multi-tasking (Multithreading)

•Executing several tasks simultaneously where each task is a separate


independent part of the same program is called Thread-based multitasking
and each independent part is called Thread.

•The main goal of multi-tasking is to make or do a better performance of the


system by reducing response time.

•Threads share the same address space. A thread is light weight and cost of
communication between the thread is low.
Different between Multitasking and Multithreading
FEATURES MULTITASKING MULTITHREADING
Definition When a single processor does many jobs Multitasking occurs when the CPU does
(program, threads, process, task) at the many tasks, such as a program, process,
same time, it is referred to as task, or thread.
multitasking.
Basic A CPU may perform multiple tasks at Multithreading allows a CPU to generate
once by using the multitasking method. numerous threads from a job and process
them all at the same time.
Resources and The system must assign different The system assigns a single memory
Memory resources and memory to separate block to each process.
programs that are running concurrently in
multitasking.
Switching CPU switches between programs CPU switches between the threads
frequently. frequently.
Speed of Execution It is comparatively slower in execution. It is comparatively faster in execution.
Working A user may easily run several jobs off of A CPU has the ability to split a single
their CPU at once. program into several threads to improve
its functionality and efficiency.
Process The process of terminating a task takes It requires considerably less time to end a
Termination comparatively more time. process.
LIFE CYCLE OF A THREAD
A thread can be in any of the following states:
 New

 Runnable

 Running

 Blocked

 Waiting

 Timed Waiting

 Terminated
Explanation
• New: A newly created thread that has not yet started the execution. It
remains in this state until the program starts the thread using start()
method.
• It is also referred to as a born thread.

• Runnable: If a thread is in this state it means that the thread is ready for
execution and waiting for the availability of the processor.

• If all threads in queue are of same priority then they are given time slots for
execution in round robin fashion.
• Running: It means that the processor has given its time to the thread for execution. A
thread keeps running until the following conditions occurs:

(a) Thread give up its control on its own and it can happen in the following situations:
• A thread gets suspended using suspend() method which can only be revived using
resume() method.
• A thread is made to sleep for a specified period of time using sleep(time)

• method, where time is specified in milliseconds.


• A thread is made to wait for some event to occur using wait () method. In this
case a thread can be scheduled to run again using notify() method.

(b) A thread is pre-empted by a higher priority thread.


• Blocked: If a thread is prevented from entering into runnable state or waiting for I/O to
complete, then a thread is said to be in Blocked state. A thread in this state cannot continue its
execution until it is moved to runnable state. Any thread
• in these states does not consume any CPU cycle.
• Waiting: A thread waits indefinitely for another thread to perform a task. A thread transitions back
to the runnable state only when another thread signals the waiting thread to continue executing.

• Timed Waiting: A thread that is waiting for another thread to perform a task for a specified
interval of time. A thread in this state transitions back to the runnable state when that time interval
expires or when the event it is waiting for occurs.

• Terminated: A runnable thread enters the dead or terminated state when it successfully

completes its task or otherwise terminated due to any error or even forcefully killed.
THREAD-LIFE CYCLE
The Main() thread
• When we run any java program, the program begins to execute its code starting from the
main method.

• Therefore, the JVM creates a thread to start executing the code present in main method. This
thread is called as main thread.

•Although the main thread is automatically created, it can be controlled by obtaining a


reference to it by calling currentThread() method.

Two important things to know about main thread are,

• It is the thread from which other threads will be produced.

• main thread must be always the last thread to finish execution.


CREATION OF THREAD
THREAD PRIORITIES Min:1
Default:5
Max:10

• Thread priorities are integers which decide how one thread should be treated with respect to
the others.

• Thread priority decides when to switch from one running thread to another, and the process is
called context switching.
• A thread can voluntarily release control and the highest priority thread that is ready to run is
given the CPU.
• A thread can be preempted by a higher priority thread no matter what the lower priority
thread is doing. Whenever a higher priority thread wants to run it does.
• To set the priority of the thread, setPriority() method is used which is a method of the class
Thread Class.
• In place of defining the priority in integers, we can use MIN_PRIORITY with value 1,
NORM_PRIORITY(Default Priority) with value 5, MAX_PRIORITY with value 10
Get and Set Thread Priority

• int getPriority(): Thread.getPriority() method returns priority of given


thread.

• void setPriority(int newPriority): Thread.setPriority() method changes


the priority of thread to thevalue new Priority.

• This method throws IllegalArgumentException if valueof parameter


new Priority goes beyond minimum(1) and maximum(10) limit.
Thread Synchronization

•There are two types of thread synchronization namely mutual exclusive and
inter- thread communication.
• Mutual Exclusive
 Synchronized method.

 Synchronized block.

 Static synchronization.

• Cooperation (Inter-thread communication in java)


1. Mutual Exclusive helps keeping threads from interfering with one another while sharing
data. This can be done by three ways in java:

 by synchronized method

 by synchronized block

 by static synchronization

Synchronized method:
• If you declare any method as synchronized, it is known as synchronized method.
Synchronized method is used to lock an object for any shared resource.

• When a thread invokes a synchronized method, it automatically acquires the lock

• for that object and releases it when the thread completes its task.
Synchronized Block

Syntax for synchronized block


synchronized (object reference expression)
{
//code block
}
STATIC SYNCHRONIZATION
INTER-THREAD COMMUNICATION

Definition
• Inter-Thread communication or Co-operation is defined as the
process of allowing synchronized threads to communicate with each
other.

• It is a mechanism in which a thread is paused running in its critical


section and another thread is allowed to enter (or lock) in the same
critical section to be executed.
Methods of Object class used to implement Inter-Thread
Communication

Inter-Thread Communication can be implemented by following


methods of Object class

 wait()
 notify()
 notifyAll()
• wait() Method causes current thread to release the lock and wait until
either another thread invokes the notify() method or the notifyAll()
method for this object, or a specified amount of time has elapsed.

Syntax:
public final void wait()throws InterruptedException
public final void wait(long timeout)throws
InterruptedException
• notify() method wakes up a single thread that is waiting on this
object's monitor. If any threads are waiting on this object, one of them
is chosen to be awakened.
Syntax: public final void notify()

 notifyAll() wakes up all the threads that called wait() on the same
object.
Syntax: public void notifyAll()
Understanding the process of inter-thread communication

The point to point explanation of the above diagram is as


follows:
1.Threads enter to acquire lock.
2.Lock is acquired by on thread.
3.Now thread goes to waiting state if you call wait() method on
the object. Otherwise it releases the lock and exits.
4.If you call notify() or notifyAll() method, thread moves to the
notified state (runnable state).
5.Now thread is available to acquire lock.
6.After completion of the task, thread releases the lock and exits
the monitor state of the object.
Difference between wait and sleep?

wait() sleep()

The wait() method releases the lock. The sleep() method doesn't release the
lock.

It is a method of Object class It is a method of Thread class

It is the non-static method It is the static method

It should be notified by notify() or After the specified amount of time,


notifyAll() methods sleep is completed.
Example for Inter-Thread Communication (Producer Consumer
Problem)

• Producer-consumer problem (also known as the bounded-buffer


problem) is a classic example of a multi-process synchronization
problem

• The problem describes two processes, the producer and the


consumer, which share a common, fixed-size buffer used as a queue
• The producer’s job is to generate data, put it into the buffer, and start
again

• At the same time, the consumer is consuming the data (i.e. removing
it from the buffer), one piece at a time.

While implementing, the following two


conditions should be satisfied:

 Producer should not try to add data


into the buffer when it is full
 Consumer should not try to remove
data from an empty buffer
PROGRAM FOR PRODUCER CONSUMER PROBLEM
IMPLEMENTATION
OUTPUT
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3

INPUT/ OUTPUT BASICS
• Java I/O (Input and Output) is used to process the input and produce the output.

• Java uses the concept of a stream to make I/O operation fast.

• The java.io package contains all the classes required for input and output operations.
Stream
• A stream can be defined as a sequence of data.
There are two kinds of Streams −

1.InputStream − The InputStream is used to read data from a source.

2.OutputStream − The OutputStream is used for writing data to a destination.


Byte Streams

• Java byte streams are used to perform input and output of 8-bit bytes.
Though there are many classes related to byte streams but the most
frequently used classes are,

• FileInputStream and FileOutputStream.


• Following is an example which makes use of these two classes to
copy an input file into an output file
import java.io.*;
public class CopyFile {
Now let's have a file input.txt with the
public static void main(String args[]) throws
IOException { following content −
FileInputStream in = null; FileOutputStream out = null;
This is test for copy file.
try {
in = new FileInputStream("input.txt"); As a next step, compile the above
out = new FileOutputStream("output.txt"); int c; program and execute it, which will
while ((c = in.read()) != -1) { result in
out.write(c);
} creating output.txt file with the same
}finally { content as we have in input.txt. So
if (in != null) { let's put
in.close();
the above code in CopyFile.java file
}
if (out != null) {
and do the following −
out.close(); $javac CopyFile.java
}
}
$java CopyFile
}
}
Character Streams

• Java byte streams are used to perform input and output of 8-bit bytes, whereas Java Character

streams are used to perform input and output for 16-bit unicode.

• Though there are many classes related to character streams but the most frequently used classes

are, FileReader and FileWriter. Though internally FileReader uses FileInputStream and

FileWriter uses FileOutputStream but here the major difference is that FileReader reads two bytes

at a time and FileWriter writes two bytes at a time.


EXAMPLE
Now let's have a file input.txt with the
following content −
This is test for copy file.
As a next step, compile the above
program and execute it, which will
result in creating output.txt file with
the same content as we have in
input.txt. So let's put the above code
in CopyFile.java file and do the
following −

$javac CopyFile.java

$java CopyFile
Standard Streams

•All the programming languages provide support for standard I/O where the user's
program can take input from a keyboard and then produce an output on the
computer screen.

• In Java, 3 streams are created for us automatically with the console.

1)System.out: standard output stream

2)System.in: standard input stream

3)System.err: standard error stream


Example

System.out.println("simple message");
int i=System.in.read();//returns ASCII code of 1st character
System.out.println((char)i);//will print the character
System.err.println("error message");
Reading and Writing Console
• Reading Console Input:
The preferred method of reading console input is to use a character-oriented
stream.

•There are three different ways for reading input from the user in the command line
environment(console).
1.Using Buffered Reader Class
2.Using Scanner Class
3.Using Console Class
Reading and Writing Console
Reading Console Input:
The preferred method of reading console input is to use a character-oriented
stream.
There are three different ways for reading input from the user in the command
line environment(console).
1.Using Buffered Reader Class
2.Using Scanner Class
3.Using Console Class
1.Using Buffered Reader Class

•In Java, console input is accomplished by reading from System.in. To obtain a


character based stream that is attached to the console, wrap System.in in a
BufferedReader object.

•BufferedReader supports a buffered input stream. Its most commonly used


constructor is shown here:
BufferedReader(Reader inputReader)
• Here, inputReader is the stream that is linked to the instance of BufferedReader that is
being created. Reader is an abstract class. One of its concrete subclasses is
InputStreamReader, which converts bytes to characters.

• To obtain an InputStreamReader object that is linked to System.in, use the following


constructor.

InputStreamReader(InputStream inputStream)

• Because System.in refers to an object of type InputStream, it can be used for


inputStream. Putting it all together, the following line of code creates a
BufferedReader that is connected to the keyboard:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


Input Computer
Output Computer
Writing Console Output
•Console output is most easily accomplished with print() and println() methods. These methods are
defined by the class PrintStream which is the type of object referenced by System.in.

•Even though System.out is a byte stream, using it for a simple program output is still acceptable.

•Because the PrintStream is an output stream derived from the OutputStream, it also implements the
low-level method write(). Thus, write() can be used to write to the console.

•The simplest form of write() defined by the PrintStream is shown below :

•void write(int byteval)

•This method writes the byte specified by byteval. Although byteval is declared as an integer, only
the low-order eight bits are written.
Example

You will not often use write() to perform console


output (although doing so might be useful in some
situations) because print() and println() are
substantially easier to use.
Reading and Writing Files
A stream can be defined as a sequence of data. The InputStream is used to read data from a source and the OutputStream is
used for writing data to a destination.

Here is a hierarchy of classes to deal with Input and Output streams.


FileOutputStream
• FileOutputStream is used to create a file and write data into it. The stream would
create a file, if it doesn't already exist, before opening it for output.
• Here are two constructors which can be used to create a FileOutputStream object.
Following constructor takes a file name as a string to create an input stream
object to write the file −
• OutputStream f = new FileOutputStream("C:/java/hello")
• Following constructor takes a file object to create an output stream object to write
• the file. First, we create a file object using File() method as follows −
• File f = new File("C:/java/hello");
• OutputStream f = new FileOutputStream(f);
• Once you have OutputStream object in hand, then there is a list of helper
methods, which can be used to write to stream or to do other operations on the
There are other important output streams available, for more detail you can refer
to the following links

• ByteArrayOutputStream

• DataOutputStream
Example

The above code would create file test.txt and


would write given numbers in binary format.
Same would be the output on the stdout
screen.
SUMMARY
Generic Programming
• Generic programming enables the programmer to create classes, interfaces and methods that
automatically works with all types of data(Integer, String, Float etc).
• It has expanded the ability to reuse the code safely and easily.
Advantages
There are 3 main advantages of Java generics
Type-safety: We can hold only a single type of objects in generics. It doesn’t allow to store other
objects
Type casting is not required: There is no need to typecast the object
Compile-Time Checking: It is checked at compile time so problem will not occur at runtime.
Generic class

• A generic class is a class with one or more type variables.


• Generics means parameterized types.
• Parameterized types enables to create classes, interfaces, and methods in which the type of data upon
which they operate is specified as a parameter.
• Class, interface, or method that operates on a parameterized type is called generic, as in generic class
or generic method.
Syntax for declaring a generic class:
class class-name<type-param-list >
{ // …
Syntax for declaring a reference to a generic class:
class-name<type-arg-list > var-name =new class-name<type-arg-list >(cons-arg- list);
}
// A simple generic class. public class GenDemo
// Here, T is a type parameter that {
class Gen<T> public static void main(String[] args)
{ {
T ob; // declare an object of type T Gen(T o) // Create a Gen reference for Integers.
{ Gen<Integer> iOb= new Gen<Integer>(88); iOb.showType();
ob = o; int v = iOb.getob(); System.out.println("value: " + v);
} // Create a Gen object for Strings.
// Return ob. T getob() Gen<String> strOb = new Gen<String> ("RMDEC");
{ strOb.showType();
return ob; String str = strOb.getob(); System.out.println("value: " + str);
} }
// Show type of T. }
void showType() Output:
{ Type of T is java.lang.Integer value: 88
System.out.println("Type of T is " +ob.getClass().getName()); Type of T is java.lang.String value: RMDEC
}}
A Generic Class with Two Type Parameters
It is possible to declare more than one type parameter in a generic type. To specify two or more type
parameters, simply use a comma-separated list.
class TwoGen<T, V>
{
T ob1; V ob2;
TwoGen(T o1, V o2)
{
ob1 = o1; ob2 = o2;
}
void showTypes()
{
System.out.println("Type of T is “ +ob1.getClass().getName());
System.out.println("Type of V is " +ob2.getClass().getName());
}
T getob1()
{
return ob1;
} int v = tgObj.getob1();
V getob2() System.out.println("value: " + v);
{ String str = tgObj.getob2();
return ob2; System.out.println("value: " + str);
} }
}
}
public class GenDemo
{
public static void main(String[] args)
{
// Create a Gen reference for Integers.
TwoGen<Integer, String> tgObj =new TwoGen<Integer, String>
(88, " R.M.D Engineering College");
tgObj.showTypes();
Output:
Type of T is java.lang.Integer
Type of V is java.lang.String value: 88
value: R.M.D Engineering College
Explanation:
Here, class TwoGen<T, V> has two type parameters: T and V, separated by a comma. Because it has two type
parameters, two type arguments must be passed to TwoGen when an object is created. In this case, Integer is
substituted
for T, and String is substituted for V.
Generic methods

• Methods inside a generic class can make use of a class’ type parameter and are, therefore,
automatically generic relative to the type parameter.
• However, it is possible to declare a generic method that uses one or more type parameters of its
own.
• The scope of arguments is limited to the method where it is declared. It allows static as well as
non-static methods.
Syntax for a generic method:
<type-parameter> return_type method_name (parameters)
{
...
}
class Demo
{
static <V, T> void display (V v, T t)
{
System.out.println(v.getClass().getName()+" = " +v);
System.out.println(t.getClass().getName()+" = " +t);
}
public static void main(String[] args)
{
display(88," R.M.D Engineering College ");
}
}

Output:
java lang.Integer = 88
java lang.String = R.M.D Engineering College
Example 2
Following example illustrates how we can print an array of different type using a single Generic method
public class GenericMethodTest
{
// generic method printArray
public static < E > void printArray( E[] inputArray )
{
// Display array elements for(E element : inputArray)
{
System.out.printf("%s ", element);
}
System.out.println();
}
public static void main(String args[]) Output
{ Array integerArray contains:
12345
// Create arrays of Integer, Double and Character Array doubleArray contains:
Integer[] intArray = { 1, 2, 3, 4, 5 }; 1.1 2.2 3.3 4.4
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Array characterArray contains:
RMDEC
Character[] charArray = { 'R', 'M', 'D', 'E', 'C' };

System.out.println("Array integerArray contains:");


printArray(intArray); // pass an Integer array

System.out.println("Array doubleArray contains:");


printArray(doubleArray); // pass a Double array

System.out.println("Array characterArray contains:");


printArray(charArray); // pass a Character array
}
}
Bounded Types

• In Java Generics it is possible to set restriction on the type that will be allowed to pass to a type-parameter. This is
done with the help of extends keyword when specifying the type parameter.
< T extends Number >
• Here we have taken Number class, it can be any wrapper class name. This
• specifies that T can be only be replaced by Number class data itself or any of its subclass.
Example:
• Create a generic class that contains a method that returns the average of an array of numbers.
class Stats<T extends Number>
{
T[] nums; // array of Number or subclass
Stats(T[] o)
{
nums = o;
}
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++) sum += nums[i].doubleValue(); return sum / nums.length;
}
}
public class GenDemo
{
public static void main(String[] args)
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Stats<Integer> iob = new Stats<Integer>(inums);
double v = iob.average();
System.out.println("iob average is " + v);
Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Double> dob = new Stats<Double>(dnums);
double w = dob.average();
System.out.println("dob average is " + w);
}
}
Generic Interface
Comparable interface is a great example of Generics in interfaces and it’s written as:
Package
import java.util*;
public interface Comparable<T>
{
public int compareTo(T o);
}
In similar way, we can create generic interfaces in java. We can also have multiple type parameters as in
Map interface. Again we can provide parameterized value to a parameterized type also, for example new
HashMap<String, List<String>>(); is valid.
Restrictions and Limitations
There are a few restrictions that you need to keep in mind when using generics.
They involve creating objects of a type parameter, static members, exceptions, and arrays.
Type Parameters Can’t Be Instantiated
It is not possible to create an instance of a type parameter.
For example, consider this class: class Gen<T>
{
T ob; Gen()
{
ob = new T(); // Illegal!!!
}
}
Here, it is illegal to attempt to create an instance of T. The reason is since T does not exist at run time, how the
compiler doesn’t know what type of object to create.
Restrictions on Static Members
No static member can use a type parameter declared by the enclosing class. For example,both of the static members of this

class are illegal:

class Wrong<T>

// Wrong, no static variables of type T.

static T ob;

// Wrong, no static method can use T. static T getob()

return ob;

Although we can’t declare static members that use a type parameter declared by the enclosing class, we can declare static

generic methods, which define their own type parameters.


Generic Array Restrictions
There are two important generics restrictions that apply to arrays.
First, you cannot instantiate an array whose element type is a type parameter. Second, you cannot create an array of
type-specific generic references. The following short program shows both situations:
// Generics and arrays.
class Gen<T extends Number>
{
T ob;
T vals[]; // OK Gen(T o, T[] nums)
{
ob = o;
// This statement is illegal.
// vals = new T[10]; // can't create an array of T
// But, this statement is OK.
vals = nums; // OK to assign reference to existent array
}
}
class GenArrays
{
public static void main(String args[])
{
Integer n[] = { 1, 2, 3, 4, 5 };
Gen<Integer> iOb = new Gen<Integer>(50, n);
// Can't create an array of type-specific generic references.
// Gen<Integer> gens[] = new Gen<Integer>[10]; // Wrong!
// This is OK.
Gen<?> gens[] = new Gen<?>[10]; // OK
}
}
• The reason you can’t create an array of T is that T does not exist at run time, so there is no way for the compiler to
know what type of array to actually create. However, you can pass a reference to a type-compatible array to
Gen( ) when an object is created and assign that reference to vals, as the program does in this line:
Generic Exception Restriction
• A generic class cannot extend Throwable. This means that you cannot create generic exception classes.
Runtime Type Inquiry Only Works with Raw Types
• Objects in the virtual machine always have a specific nongeneric type. Therefore, all type inquiries yield only the
raw type. you will get a compiler error (with instanceof) or warning (with casts) when you try to inquire whether
an object belongs to a generic type.
Beware of Clashes after Erasure
It is illegal to create conditions that cause clashes when generic types are erased.Here is an example. Suppose
we add an equals method to the Pair class,
public class Pair<T>
{
public boolean equals(T value)
{
return first.equals(value) && second.equals(value); . . .
}
Consider a Pair<String>. Conceptually, it has two equals methods: boolean equals(String) // defined in Pair<T>
boolean equals(Object) // inherited from Object
But the intuition leads us astray. The erasure of the method boolean equals(T) is boolean equals(Object) which
clashes with the Object.equals method. The remedy is, to rename the offending method.

You might also like