类定义
类是模板、是对象共同特征的抽取,对象是类的具体化、实例化。
1.
pulic class 类名
{
数据成员
pulic 方法成员(类名 参数)
{
}
2.public 类名(数据成员)//构造器,返回值什么都不能写,void也不能写
}
准则:任何类必须要有至少一个构造器,以实现空间初始化。
如果一个类没有定义任何构造器,则编译器自动帮你生成一个(称为默认或无参构造器)。
新建
例:求两点间距离。
public class Point{
protected int x;
protected int y;
public getDistance(Point p){
return Math.sqrt((this.x - p.x)*(this.x - p.x)
+(this.y - p.y)*(this.y - p.y)
);
}
public Point(int x,int y){//当实例变量和方法参数名称相同时,使用 “this” 关键字来引用实例变量。在构造函数中,使用 “this” 关键字调用其他构造函数,但必须是在构造方法的第一行出现。
this.x=x;
this.y=y;
}
}
(可以添加后面提到的默认构造器的重载)
调用:
public static void main(String[] args){
Point p1,p2;
p1=new Point(1,2);
p2=new Point(2,3);
double d=p1.getDistance(p2);//p1就是隐蔽的this
System.out.println("distance="+d);
}
成员变量
成员方法
(常考)static静态的-类的数据成员
1)数量:一个类中只有一份
2)生命期:类加载到内存中,诞生;从内存中移除,死亡。
3)调用格式:类名.成员名 如Point.w
vs 对象的数据成员
1)数量:每一个对象,都包含对象的数据成员,有多少个对象就有多少份数据成员
2)生命期:创建对象时,诞生;对象空间回收时,死亡。
3)调用格式:对象引用.数据成员 如p1.x
在对象的方法成员中包含this,类的数据成员和对象的数据成员都可以直接用。
在类的方法成员中没有this,可以直接使用类的数据成员,但只能间接调用对象成员。
四种修饰符
- public表示该属性或方法可以被任何其他类访问;
- private表示只有类自身的方法可以访问该属性或方法
- protected表示该属性或方法可以被同一个包内的类和不同包中的子类访问
- 默认表示该属性或方法可以被同一个包内的类访问。
数据成员尽可能地隐藏,方法成员尽可能地公开。
main方法
重写和重载
重载是在同一个类中定义多个方法,方法名相同但参数列表(类型或次序或个数)不同,目的是提供不同的方法重载形式;一个方法在所在的类中可以被重载多次。
构造方法能被重载,但不能被重写。
构造器的重载:
public Point(int x){
this(x,0);
}
public Point(){
this(0);//this(0,0);
}
这就是默认构造器,最好也写一下。
参数构造器
public class ColorPoint extends Point{
protected int c;
public ColorPoint(int x,int y,int c){
super(x,y);//调用父类的两个参数的构造器
this.c=c;
}
public ColorPoint(int x,int y){
this(x,y,0);
}
public ColorPoint(){
this(0,0);
}
}
例:读重载相关程序写出打印结果
根据数据类型
1.int
2.double:3L是long型,这里会自动类型转换,根据(byte-char/short-int-long-float-double)不断向上找到数据类型为double
3.int
4.int[]
5.int[]:更特殊的数据类型优先,因为int []是一个Object但Object不一定是int[],也就是说int[]范围更窄更特殊
而重写是子类对父类方法的重新实现,目的是改变方法的行为。
必须是非静态static成员的对象方法
必须方法名、参数相同,返回值类型相容
必须能够被子类继承(也就是说能从子类中访问出来)
例:读重写相关程序写结果
public class TA{
protected int x=1;
public void f(){System.out.println("TA-f()");}
public static void g(){System.out.println("TA-g()");}
}
public class TB extends TA{
protected int x=2;
public void f(){System.out.println("TB-f()");}
public static void g(){System.out.println("TB-g()");}
}
问在main中执行以下代码,表示结果:
代码1:
TB t=new TB;//前一个TB是定义时的类型,后一个是运行时的类型
System.out.println(t.x);//2
t.f();//TB-f()
t.g();//TB-g()
TB.g();//TB-g()
代码2:
TA t=new TB;//TA是定义时的类型同时也是父,TB是运行时的运行同时也是子(重点理解)
System.out.println(t.x);//1,访问的是定义的类型,也就是父亲TA
t.f();//TB-f(),因为是f()方法重写,访问的是运行时的类型,也就是儿子TB,牢记原则:子对象代替父对象使用!
t.g();//TA-g(),因为static类方法没有重写只有隐藏,这里显示定义时的类型
TA.g();//TA-g()
例:对比重载重写,读程序写结果
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
public void draw(String color) {
System.out.println("Drawing a shape with color: " + color);
}
}//重载
class Circle extends Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}//重写
public class OverloadingVsOverriding {
public static void main(String[] args) {
Shape shape = new Shape();
shape.draw(); // Output: Drawing a shape
shape.draw("red"); // Output: Drawing a shape with color: red
Circle circle = new Circle();
circle.draw(); // Output: Drawing a circle
//展示了多态的概念,其中运行时决定调用的是子类的方法。
Shape shapeCircle = new Circle();
shapeCircle.draw(); // Output: Drawing a circle
shapeCircle.draw("blue"); // Output: Drawing a shape with color: blue
}
}
抽象类和接口
只声明而没有实现的方法称为抽象方法,抽象方法必须使用abstract关键字来修饰,用abstract修饰的类称为抽象类,抽象类的子类必须实现父类的所有抽象方法后才能实例化,否则这个子类也成为一个抽象类。
如果一个抽象类中的所有方法都是抽象的,即接口。接口是由常量和抽象方法组成的特殊类,是对抽象类的进一步抽象。接口可以继承其他的接口,并添加新的属性和抽象方法。
1.实现方法:
(1)抽象类中不是所有的方法都是抽象方法,可以在抽象类中声明并实现方法,也可以有被abstract修饰的方法(抽象方法),因为存在抽象方法,所以该类必须是抽象类。
(2)接口要求只能包含抽象方法,抽象方法是指没有实现的方法。接口就根本不能存在方法的实现。
2.子类使用的关键词不一样:
(1)实现抽象类使用extends关键字来继承抽象类。
(2)子类使用关键字implements来实现接口。
3.是否有构造器:
(1)抽象类可以有构造器,它属于类,有类的所有特性(但是不能实例化),包括类的构造方法。
(2)接口不能有构造器
4.子类能继承的数量:
(1)抽象类只有单继承,子类只能继承一个父类。
(2)接口就可以实现多继承,一个类可以实现多个接口。
5.可使用的修饰符:
(1)抽象方法可以有public、protected这些修饰符
(2)接口方法默认修饰符是public,不可以使用其它修饰符。
6.速度方面:
抽象方法比接口速度要快
例:构造计算圆形面积的基本抽象类和接口
//Graphix.java
public abstract class Graphix {
public abstract double area() ;
}
//Areable.java
public interface Areable {
double area();
}
//Circle.java
/*
public class Circle extends Graphix{
@Override
public double area() {
System.out.println("圆面积公式");
return 0;
}
}
*///分别测试运行
public class Circle implements Areable
{
@Override
public double area() {
System.out.println("圆面积公式");
return 0;
}
}
例:Dog
类同时继承自Animal
抽象类并实现AnimalBehavior
接口
// 抽象类
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public abstract void sound();
}
// 接口,更名为AnimalBehavior以避免命名冲突
interface AnimalBehavior {
int ID = 1; // 接口字段默认是 static 和 final 的
void breathe();
void run();
}
// Dog类实现AnimalBehavior接口
class Dog implements AnimalBehavior {
// 实现接口中的方法
public void breathe() {
System.out.println("Dog is breathing!");
}
public void run() {
System.out.println("Dog is running.");
}
public void sound() {
System.out.println("Dog barks!");
}
}
public class Example1 {
public static void main(String args[]) {
Dog dog = new Dog();
dog.breathe();
dog.run();
dog.sound();
}
}
输出结果为
Dog is breathing!
Dog is running.
Dog barks!
展示了Dog
类实例化的对象调用了breathe
、run
和sound
方法,并且按照这些方法中定义的打印语句输出了相应的文本。
继承与多态
继承
修饰符 class 子类名 extends 父类名;
类之间只能有单一继承,不支持多重继承。一个类没有明确表示继承,则默认从object类中继承。
多态是同一个行为具有多个不同表现形式或形态的能力。有两个关键因素:继承和方法重写,继承指的是子类可以继承父亲的方法和属性,方法重写指的是子类可以重写父亲中的方法,实现自己的独特属性。
class Animal {
public void Sound() {
System.out.println("Animal barks");
}
}
class Dog extends Animal {
public void Sound() {
System.out.println("Dog barks");
}
}
public class Example {
public static void main(String[] args) {
Animal a1 = new Dog();
a1.Sound(); // 调用Animal类中定义的Sound方法
}
}
这段代码的输出结果为 Dog barks
Dog类继承自Animal类并覆盖了Sound方法,所以当创建Dog类的实例并赋值给Animal类型的对象时,调用Sound方法将输出Dog barks。