Java Language
Klassen en objecten
Zoeken…
Invoering
Objecten hebben toestanden en gedragingen. Voorbeeld: een hond heeft toestanden - kleur, naam, ras en gedrag - kwispelende staart, blaffen, eten. Een object is een instantie van een klasse.
Klasse - Een klasse kan worden gedefinieerd als een sjabloon / blauwdruk die het gedrag / de status beschrijft die het object van zijn type ondersteunt.
Syntaxis
- class Voorbeeld {} // class trefwoord, naam, body
Eenvoudigst mogelijke klasse
class TrivialClass {}
Een klasse bestaat bij een minimum van de class
zoekwoord, een naam en een lichaam, dat is misschien leeg.
U instantieert een klas met de new
operator.
TrivialClass tc = new TrivialClass();
Objectlid versus statisch lid
Met deze les:
class ObjectMemberVsStaticMember {
static int staticCounter = 0;
int memberCounter = 0;
void increment() {
staticCounter ++;
memberCounter++;
}
}
het volgende codefragment:
final ObjectMemberVsStaticMember o1 = new ObjectMemberVsStaticMember();
final ObjectMemberVsStaticMember o2 = new ObjectMemberVsStaticMember();
o1.increment();
o2.increment();
o2.increment();
System.out.println("o1 static counter " + o1.staticCounter);
System.out.println("o1 member counter " + o1.memberCounter);
System.out.println();
System.out.println("o2 static counter " + o2.staticCounter);
System.out.println("o2 member counter " + o2.memberCounter);
System.out.println();
System.out.println("ObjectMemberVsStaticMember.staticCounter = " + ObjectMemberVsStaticMember.staticCounter);
// the following line does not compile. You need an object
// to access its members
//System.out.println("ObjectMemberVsStaticMember.staticCounter = " + ObjectMemberVsStaticMember.memberCounter);
produceert deze output:
o1 static counter 3
o1 member counter 1
o2 static counter 3
o2 member counter 2
ObjectMemberVsStaticMember.staticCounter = 3
Opmerking: u moet geen static
leden op objecten aanroepen, maar op klassen. Hoewel het voor de JVM geen verschil maakt, zullen menselijke lezers het waarderen.
static
leden maken deel uit van de klas en bestaan slechts eenmaal per klas. Niet- static
leden bestaan op instanties, er is een onafhankelijke kopie voor elke instantie. Dit betekent ook dat u toegang tot een object van die klasse nodig hebt om toegang te krijgen tot zijn leden.
Overbelasting methoden
Soms moet dezelfde functionaliteit worden geschreven voor verschillende soorten invoer. Op dat moment kan men dezelfde methodenaam gebruiken met een andere set parameters. Elke verschillende set parameters staat bekend als een methodehandtekening. Zoals te zien in het voorbeeld, kan een enkele methode meerdere handtekeningen hebben.
public class Displayer {
public void displayName(String firstName) {
System.out.println("Name is: " + firstName);
}
public void displayName(String firstName, String lastName) {
System.out.println("Name is: " + firstName + " " + lastName);
}
public static void main(String[] args) {
Displayer displayer = new Displayer();
displayer.displayName("Ram"); //prints "Name is: Ram"
displayer.displayName("Jon", "Skeet"); //prints "Name is: Jon Skeet"
}
}
Het voordeel is dat dezelfde functionaliteit wordt aangeroepen met twee verschillende aantallen ingangen. Bij het aanroepen van de methode volgens de invoer die we doorgeven (in dit geval een stringwaarde of twee stringwaarden) wordt de overeenkomstige methode uitgevoerd.
Methoden kunnen worden overbelast:
Op basis van het aantal doorgegeven parameters .
Voorbeeld:
method(String s)
enmethod(String s1, String s2)
.
Gebaseerd op de volgorde van parameters .
Voorbeeld:
method(int i, float f)
enmethod(float f, int i))
.
Opmerking: Methoden kunnen niet worden overbelast door alleen het retourtype te wijzigen ( int method()
wordt als hetzelfde beschouwd als String method()
en zal een RuntimeException
als dit wordt geprobeerd). Als u het retourtype wijzigt, moet u ook de parameters wijzigen om te overbelasten.
Constructie en gebruik van basisobjecten
Objecten komen in hun eigen klasse, dus een eenvoudig voorbeeld zou een auto zijn (gedetailleerde uitleg hieronder):
public class Car {
//Variables describing the characteristics of an individual car, varies per object
private int milesPerGallon;
private String name;
private String color;
public int numGallonsInTank;
public Car(){
milesPerGallon = 0;
name = "";
color = "";
numGallonsInTank = 0;
}
//this is where an individual object is created
public Car(int mpg, int, gallonsInTank, String carName, String carColor){
milesPerGallon = mpg;
name = carName;
color = carColor;
numGallonsInTank = gallonsInTank;
}
//methods to make the object more usable
//Cars need to drive
public void drive(int distanceInMiles){
//get miles left in car
int miles = numGallonsInTank * milesPerGallon;
//check that car has enough gas to drive distanceInMiles
if (miles <= distanceInMiles){
numGallonsInTank = numGallonsInTank - (distanceInMiles / milesPerGallon)
System.out.println("Drove " + numGallonsInTank + " miles!");
} else {
System.out.println("Could not drive!");
}
}
public void paintCar(String newColor){
color = newColor;
}
//set new Miles Per Gallon
public void setMPG(int newMPG){
milesPerGallon = newMPG;
}
//set new number of Gallon In Tank
public void setGallonsInTank(int numGallons){
numGallonsInTank = numGallons;
}
public void nameCar(String newName){
name = newName;
}
//Get the Car color
public String getColor(){
return color;
}
//Get the Car name
public String getName(){
return name;
}
//Get the number of Gallons
public String getGallons(){
return numGallonsInTank;
}
}
Objecten zijn exemplaren van hun klasse. Dus, de manier waarop je een object zou maken, zou zijn door de Car-klasse op een van twee manieren in je hoofdklasse aan te roepen (hoofdmethode in Java of onCreate in Android).
Optie 1
`Car newCar = new Car(30, 10, "Ferrari", "Red");
Optie 1 is waar u het programma in wezen alles vertelt over de auto bij het maken van het object. Als u een eigenschap van de auto wilt wijzigen, moet u een van de methoden aanroepen, zoals de methode repaintCar
. Voorbeeld:
newCar.repaintCar("Blue");
Opmerking: zorg ervoor dat u het juiste gegevenstype doorgeeft aan de methode. In het bovenstaande voorbeeld kunt u ook een variabele doorgeven aan de methode repaintCar
zolang het gegevenstype correct is` .
Dat was een voorbeeld van het veranderen van eigenschappen van een object, het ontvangen van eigenschappen van een object zou een methode uit de Car-klasse vereisen die een retourwaarde heeft (wat betekent dat een methode niet void
). Voorbeeld:
String myCarName = newCar.getName(); //returns string "Ferrari"
Optie 1 is de beste optie wanneer u over alle gegevens van het object beschikt op het moment van aanmaken.
Optie 2
`Car newCar = new Car();
Optie 2 krijgt hetzelfde effect, maar vereist meer werk om een object correct te maken. Ik wil deze constructeur in de autoklasse terugroepen:
public void Car(){
milesPerGallon = 0;
name = "";
color = "";
numGallonsInTank = 0;
}
Merk op dat u geen parameters in het object hoeft door te geven om het te maken. Dit is erg handig als u niet alle aspecten van het object hebt, maar u wel de onderdelen moet gebruiken die u wel hebt. Hiermee worden generieke gegevens in elk van de instantievariabelen van het object geplaatst, zodat er geen fouten worden gegenereerd als u een stuk gegevens oproept dat niet bestaat.
Opmerking: vergeet niet dat u de delen van het object later moet instellen waarmee u het niet hebt geïnitialiseerd. Bijvoorbeeld,
Car myCar = new Car();
String color = Car.getColor(); //returns empty string
Dit is een veel voorkomende fout bij objecten die niet met al hun gegevens zijn geïnitialiseerd. Fouten werden vermeden omdat er een Constructor is waarmee een leeg Car-object kan worden gemaakt met stand-in variabelen ( public Car(){}
), maar geen enkel onderdeel van de myCar is aangepast. Correct voorbeeld van het maken van een auto-object:
Car myCar = new Car();
myCar.nameCar("Ferrari");
myCar.paintCar("Purple");
myCar.setGallonsInTank(10);
myCar.setMPG(30);
En, ter herinnering, verkrijg de eigenschappen van een object door een methode in uw hoofdklasse aan te roepen. Voorbeeld:
String myCarName = myCar.getName(); //returns string "Ferrari"
constructors
Constructors zijn speciale methoden die zijn vernoemd naar de klasse en zonder een retourtype, en worden gebruikt om objecten te construeren. Constructors kunnen, net als methoden, invoerparameters aannemen. Constructors worden gebruikt om objecten te initialiseren. Abstracte klassen kunnen ook constructors hebben.
public class Hello{
// constructor
public Hello(String wordToPrint){
printHello(wordToPrint);
}
public void printHello(String word){
System.out.println(word);
}
}
// instantiates the object during creating and prints out the content
// of wordToPrint
Het is belangrijk om te begrijpen dat constructeurs op verschillende manieren van methoden verschillen:
Constructeurs kunnen de modificaties alleen
public
,private
enprotected
en kunnen nietabstract
,final
,static
ofsynchronized
worden verklaard.Constructeurs hebben geen retourtype.
Constructors MOETEN dezelfde naam krijgen als de klassenaam. In de
Hello
voorbeeld is deHello
aannemer naam van het object is hetzelfde als de naam van de klasse.Het trefwoord
this
heeft een extra gebruik in constructors.this.method(...)
roept een methode aan op de huidige instantie, terwijlthis(...)
verwijst naar een andere constructor in de huidige klasse met verschillende handtekeningen.
Constructors kunnen ook worden opgeroepen via overerving met behulp van het trefwoord super
.
public class SuperManClass{
public SuperManClass(){
// some implementation
}
// ... methods
}
public class BatmanClass extends SupermanClass{
public BatmanClass(){
super();
}
//... methods...
}
Zie Java-taalspecificatie # 8.8 en # 15.9
Initialisatie van statische laatste velden met behulp van een statische initialisatie
Om een static final
velden te initialiseren waarvoor meer dan één expressie nodig is, kan een static
initialisatie worden gebruikt om de waarde toe te wijzen. In het volgende voorbeeld wordt een niet-wijzigbare reeks String
s geïnitialiseerd:
public class MyClass {
public static final Set<String> WORDS;
static {
Set<String> set = new HashSet<>();
set.add("Hello");
set.add("World");
set.add("foo");
set.add("bar");
set.add("42");
WORDS = Collections.unmodifiableSet(set);
}
}
Uitleggen wat methode overbelasten en negeren is.
Methode opheffen en overladen zijn twee vormen van polymorfisme ondersteund door Java.
Methode Overbelasting
Overbelasting van methoden (ook bekend als statisch polymorfisme) is een manier om twee (of meer) methoden (functies) met dezelfde naam in een enkele klasse te hebben. Ja, het is zo simpel als dat.
public class Shape{
//It could be a circle or rectangle or square
private String type;
//To calculate area of rectangle
public Double area(Long length, Long breadth){
return (Double) length * breadth;
}
//To calculate area of a circle
public Double area(Long radius){
return (Double) 3.14 * r * r;
}
}
Op deze manier kan de gebruiker dezelfde methode voor het gebied aanroepen, afhankelijk van het type vorm dat hij heeft.
Maar de echte vraag is nu, hoe zal java compiler onderscheid maken welke methode body moet worden uitgevoerd?
Nou, Java heeft duidelijk gemaakt dat hoewel de methodenamen ( area()
in ons geval) hetzelfde kunnen zijn, maar de argumenten die de methode gebruikt anders moeten zijn.
Overbelaste methoden moeten verschillende argumentenlijsten hebben (aantal en typen).
Dat gezegd hebbende, kunnen we geen andere methode toevoegen om de oppervlakte van een vierkant als deze te berekenen: public Double area(Long side)
omdat dit in dit geval conflicteert met de gebiedsmethode van cirkel en dubbelzinnigheid voor de Java-compiler veroorzaakt.
Godzijdank, er zijn wat relaxaties tijdens het schrijven van overbelaste methoden zoals
Kan verschillende retourtypen hebben.
Kan verschillende toegangsmodificaties hebben.
Kan verschillende uitzonderingen veroorzaken.
Waarom wordt dit statisch polymorfisme genoemd?
Welnu, dat komt omdat tijdens het compileren wordt besloten welke overbelaste methoden moeten worden gebruikt, op basis van het werkelijke aantal argumenten en de compilatie-tijdtypen van de argumenten.
Een van de meest voorkomende redenen om de methode te overbelasten, is de eenvoud van de code die wordt geboden. Denk bijvoorbeeld aan
String.valueOf()
waarvoor bijna elk type argument nodig is? Wat er achter de scène staat is waarschijnlijk zoiets als: -
static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(char[] data)
static String valueOf(char[] data, int offset, int count)
static String valueOf(double d)
static String valueOf(float f)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(Object obj)
Methode opheffen
Nou, methode negeren (ja je raadt het goed, het wordt ook wel dynamisch polymorfisme genoemd) is een iets interessanter en complexer onderwerp.
Bij het overschrijven van methoden overschrijven we de body van de methode die wordt aangeboden door de bovenliggende klasse. Ik snap het? Nee? Laten we een voorbeeld nemen.
public abstract class Shape{
public abstract Double area(){
return 0.0;
}
}
We hebben dus een klasse genaamd Shape en deze heeft de methode area die waarschijnlijk het gebied van de shape retourneert.
Laten we zeggen dat we twee klassen hebben genaamd Circle en Rectangle.
public class Circle extends Shape {
private Double radius = 5.0;
// See this annotation @Override, it is telling that this method is from parent
// class Shape and is overridden here
@Override
public Double area(){
return 3.14 * radius * radius;
}
}
Evenzo rechthoekklasse:
public class Rectangle extends Shape {
private Double length = 5.0;
private Double breadth= 10.0;
// See this annotation @Override, it is telling that this method is from parent
// class Shape and is overridden here
@Override
public Double area(){
return length * breadth;
}
}
Dus nu hebben beide klassen van uw kinderen de bijgewerkte methodelichaam van de ouderklasse ( Shape
). Nu is de vraag hoe het resultaat te zien? Nou laten we het op de oude psvm
manier doen.
public class AreaFinder{
public static void main(String[] args){
//This will create an object of circle class
Shape circle = new Circle();
//This will create an object of Rectangle class
Shape rectangle = new Rectangle();
// Drumbeats ......
//This should print 78.5
System.out.println("Shape of circle : "+circle.area());
//This should print 50.0
System.out.println("Shape of rectangle: "+rectangle.area());
}
}
Wauw! is het niet geweldig? Twee objecten van hetzelfde type die dezelfde methoden aanroepen en verschillende waarden retourneren. Mijn vriend, dat is de kracht van dynamisch polymorfisme.
Hier is een grafiek om de verschillen tussen deze twee beter te vergelijken: -
Methode Overbelasting | Methode opheffen |
---|---|
Methode overbelasting wordt gebruikt om de leesbaarheid van het programma te vergroten. | Methode overschrijven wordt gebruikt om de specifieke implementatie van de methode te bieden die al door de superklasse wordt geleverd. |
Overbelasting van de methode wordt binnen de klasse uitgevoerd. | Het negeren van methoden vindt plaats in twee klassen met een IS-A (overerving) relatie. |
In geval van overbelasting van de methode, moet de parameter anders zijn. | In het geval dat de methode wordt opgeheven, moet de parameter hetzelfde zijn. |
Overbelasting van de methode is het voorbeeld van compileertijdpolymorfisme. | Methode opheffen is het voorbeeld van runtime polymorfisme. |
In Java kan methode-overbelasting niet worden uitgevoerd door alleen het retourtype van de methode te wijzigen. Retourtype kan hetzelfde of verschillend zijn in methode-overbelasting. Maar u moet de parameter moeten wijzigen. | Retourtype moet hetzelfde zijn of covariant in methode negeren. |