I'll make this as short and to the point as possible, but it's kind of a complex issue. I'm writing in Java on a Linux platform, for whatever that's worth.
Short version of the goal: I want to have an abstract class called Client
that acts as a generic container for client connections. Client
should thread each of its connections. I also have some semi-tested code that plays the server counterpart to this in similar coding fashion. The abstract Client
should get implemented into something more tangible and instanceable. In my case, I have a class called FileClientGui
which extends Client
and overrides all of Client
's abstract methods with the basic method of receiving the contents of a file from the server and displaying them. This is further complicated by the fact that the abstract Client
is itself an extension of java.lang.Thread
.
So here's my file structure in generic terms:
/class/path/lib/client/Client.java
/class/path/com/fileclient/FileClientGui.java
There are several other custom classes that both of these files reference, but I'm not getting any errors out of them. If I need to post code for those items, let me know, and I'll post them.
So I run this long javac command on the terminal setting up the classpath and build directory and all of the relevant files that need to be compiled as well. The only error I receive for any of that code is this:
com/fileclient/FileClientGui.java:26: com.fileclient.FileClientGui is not abstract and does not override abstract method cleanClients() in lib.client.Client
My code (see below) clearly implements the method and all other abstract methods defined in Client.java. I scoured the Internet, and it seems like most people who encounter this error are trying to do something like implement an ActionListener
and get confused with that implementation, and many times, it's just a simple spelling or capitalization issue. I've gone over and over my code to make sure that this isn't a simple "oops" problem like that. I suspect that it's actually some kind of collision between the name of my class and the name of some other class that somehow ended up in my classpath or in Java's native framework/libraries, but I cannot find anything obvious.
At any rate, here's my code.
Client.java:
package lib.client;
import lib.clientservercore.Connection;
import lib.simplefileaccess.Logger;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.lang.Thread;
/**
*
* @author Ryan Jung
*/
public abstract class Client extends Thread {
ArrayList<Connection> connections;
boolean isRunning;
Logger log;
public Client (String logFile) {
log = new Logger(logFile);
log.write("Initializing client...");
connections = new ArrayList<Connection>(50);
log.write("Client initialized.");
}
public void logOut(String contents) {
log.write(contents);
}
public Logger getLogger() {
return this.log;
}
public ArrayList<Connection> getConnections() {
return connections;
}
public void addConnection(Connection c) {
connections.add(c);
}
public void removeConnection(Connection c) {
connections.remove(c);
}
public boolean getIsRunning() {
return isRunning;
}
public void setIsRunning(boolean r) {
isRunning = r;
}
public Connection connect(String host, int port) {
log.write("Creating new connection...");
Socket s;
Connection c = null;
// Validate port
if (port <= 1024 || port > 65536) {
log.write("Invalid server port: " + port + ". Using 12321.");
port = 12321;
}
try {
s = new Socket(host, port);
c = connectClient(s);
} catch (IOException exIo) {
log.write("Could not connect to the server at " + host + ":" + port + ". Exception: " + exIo.getMessage());
exIo.printStackTrace();
}
log.write("Connected client to " + host + ":" + port);
return c;
}
@Override
public void run() {
log.write("Running client.");
runClient();
log.write("Client finished running.");
}
abstract Connection connectClient(Socket sock);
abstract void runClient();
abstract void cleanClients();
}
FileClientGui.java:
package com.fileclient;
import lib.client.Client;
import lib.clientservercore.Connection;
import lib.clientservercore.Connection.ConnectionStatus;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Iterator;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import java.lang.Thread;
/**
*
* @author Ryan Jung
*/
public class FileClientGui extends Client {
JFrame frmMain;
JPanel pnlMain;
JPanel pnlConnect;
JTabbedPane tabConnections;
JLabel lblHost;
JLabel lblPort;
JTextField txtHost;
JTextField txtPort;
JButton btnConnect;
public FileClientGui(String logFile) {
super(logFile);
logOut("Initializing client controller...");
frmMain = new JFrame("Client");
pnlMain = new JPanel(new BorderLayout());
pnlConnect = new JPanel(new FlowLayout());
tabConnections = new JTabbedPane();
lblHost = new JLabel("Host:");
lblPort = new JLabel("Port:");
txtHost = new JTextField("localhost", 10);
txtPort = new JTextField("12321", 5);
btnConnect = new JButton("Connect");
frmMain.setSize(450, 600);
frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmMain.add(pnlMain);
pnlMain.add(pnlConnect, BorderLayout.NORTH);
pnlMain.add(tabConnections, BorderLayout.CENTER);
pnlConnect.add(lblHost);
pnlConnect.add(txtHost);
pnlConnect.add(lblPort);
pnlConnect.add(txtPort);
pnlConnect.add(btnConnect);
btnConnect.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String host = txtHost.getText();
int port = Integer.parseInt(txtPort.getText());
try {
Socket sock = new Socket(host, port);
FileClientConnectionGui c = (FileClientConnectionGui)(connectClient(sock));
tabConnections.addTab(c.getInetAddress().toString(), c.getMainPanel());
} catch (UnknownHostException ex) {
logOut("Can't find host: " + host + ". Exception: " + ex.getMessage());
ex.printStackTrace();
} catch (IOException ex) {
logOut("Exception: " + ex.getMessage());
ex.printStackTrace();
}
}
}
);
frmMain.setVisible(true);
logOut("Client controller initialized.");
}
public void removeConnection(FileClientConnectionGui c) {
logOut("Removing connection: " + c.getInetAddress().toString());
tabConnections.remove(c.getMainPanel());
logOut("Removed connection.");
}
Connection connectClient(Socket sock) {
logOut("Client controller is creating a new connection...");
FileClientConnectionGui c = new FileClientConnectionGui(sock, getLogger(), this);
addConnection(c);
c.start();
logOut("Client controller created a new connection.");
return c;
}
void runClient() {
setIsRunning(true);
logOut("Client controller is running.");
while (getIsRunning()) {
cleanClients();
try {
sleep(500);
} catch (InterruptedException ex) {
logOut("Sleep interrupted. Exception: " + ex.getMessage());
ex.printStackTrace();
}
}
logOut("Client controller stopped running.");
}
void cleanClients() {
Iterator i = getConnections().iterator();
try {
while (i.hasNext()) {
FileClientConnectionGui c = (FileClientConnectionGui)(i.next());
if (c.getStatus() == ConnectionStatus.CLOSED) {
logOut("Removing dead client at " + c.getInetAddress().toString());
tabConnections.remove(c.getMainPanel());
removeConnection(c);
}
}
} catch (Exception ex) {
logOut("cleanClients Exception: " + ex.getMessage());
}
}
}
I'll take any help I can get, and I thank you in advance for any suggestions you provide. I am thoroughly flummoxed by this.
Perhaps what is most flummoxing about this (and maybe this provides a clue to the problem?) is that I can comment out other implementations of abstract methods (runClient, for instance, or connectClient), and I get no additional problems, just the same one. Furthermore, if I add the @Override directive to one of those others like this:
@Override
Connection connectClient(Socket sock) {
logOut("Client controller is creating a new connection...");
FileClientConnectionGui c = new FileClientConnectionGui(sock, getLogger(), this);
addConnection(c);
c.start();
logOut("Client controller created a new connection.");
return c;
}
I get an additional error:
com/fileclient/FileClientGui.java:96: method does not override or implement a method from a supertype
It clearly is overriding a method from its supertype (which is Client). I've tried replacing "Client" with the full classpath (lib.client.Client) and none of the errors are changed at all.
Is there something I'm missing? Something I'm not trying?
To implement features of an abstract class, we inherit subclasses from it and create objects of the subclass. A subclass must override all abstract methods of an abstract class. However, if the subclass is declared abstract, it's not mandatory to override abstract methods.
Abstract methods cannot be overridden by a concrete subclass.
An abstract class can have an abstract method without body and it can have methods with implementation also. abstract keyword is used to create a abstract class and method. Abstract class in java can't be instantiated.
An abstract class can override Object class methods, but an interface can't.
I believe it's because you've got package-level abstract methods, which aren't visible in your subclass. Try making them protected instead.
Here's a simple pair of classes which reproduce the problem:
package x1;
public abstract class P1
{
abstract void foo();
}
And then:
package x2;
public class P2 extends x1.P1
{
void foo() {}
}
Compiling them gives:
P2.java:3: P2 is not abstract and does not override abstract method foo() in P1
public class P2 extends x1.P1
^
1 error
Making foo
protected in both classes fixes the problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With