Java类
什么是类
- 把一类事物的属性和可执行的动作结合在一起所得到的概念叫做类
- 类是抽像的, 用来模拟一类事物, 是一个概念。
- 一旦定义,类的概念就永远存在
什么是对象
- 类的一个个体
- 具体的, 实实在在存在的事物
- 生命周期短暂, 会生成和消亡
-
JAVA的类是对象的模板, 对象是类的实现
class Box { //声明类 double width; //属性 double height; double depth; } class BoxDemo { public static void main(String args[]) { Box mybox = new Box(); //创建对象 double vol; mybox.width = 10; mybox.height = 20; mybox.depth = 15; vol = mybox.width * mybox.height * mybox.depth; //调用类成员 System.out.println("Volume is " + vol); } }
声明对象
Box mybox = new Box();
java中, 所有的类对象都必须动态分配。
将一个对象的引用变量赋值给另一个对象引用变量是, 不是创建对象的实体
class Box { //声明类
double width; //属性
double height;
double depth;
}
class BoxDemo {
public static void main(String args[]) {
Box mybox1 = new Box();
mybox1.width = 10;
mybox1.height = 20;
mybox1.depth = 30;
Box mybox2 = mybox1;
System.out.println(mybox1.width + " " + mybox1.height + " " + mybox1.depth);
System.out.println(mybox2.width +" " + mybox2.height + " " + mybox2.depth);
System.out.println("mybox1.width = " + mybox1.width); //原始值
mybox2.width = 90; //通过mybox2修改width 属性 检验mybox1的width 是否改变
System.out.println("mybox2.width = " + mybox2.width); //mybox2.width 值
System.out.println("mybox1.width = " + mybox1.width); // 检验结果
System.out.println(mybox1.width + " " + mybox1.height + " " + mybox1.depth);
System.out.println(mybox2.width +" " + mybox2.height + " " + mybox2.depth);
}
}
访问控制符
类的访问控制符种类
- public
- protect
- private
- 默认(default)
在一个类的内部,所有的成员可以相互访问,访问控制是透明的;访问控制符是针对外部访问而言的
class A{
//成员之间的数据访问及函数调用是透明的
public int a1 = 10;
private int b1 = 20;
protected int c1 = 90;
public void aa() {
System.out.println("a1 = " + a1);
System.out.println("b1 = " + b1);
System.out.println("c1 = " + c1);
cc();
}
protected void bb() {
System.out.println("a1 = " + a1);
System.out.println("b1 = " + b1);
System.out.println("c1 = " + c1);
cc();
}
private void cc() {
System.out.println("a1 = " + a1);
System.out.println("b1 = " + b1);
System.out.println("c1 = " + c1);
cc();
}
}
public class TestAccess {
public static void main() {
//public成员可被外部调用
A aa = new A();
aa.a1 = 10;
// error private 成员不可被外部调用
aa.b1 = 10;
aa.cc();
}
}
外部访问包括两种方式
- 通过类名访问内部成员
- 通过类的对象名访问类的内部成员
public
- 可以通过外部访问方式访问内部的public成员
private
- 不可以通过外部访问方式访问内部的 private 成员
类的构造函数
-
类的构造函数主要用于初始化对象, 当创建对象时自动调用类的构造函数
-
构造函数,与类同名不带返回类型
-
如果类中没有定义构造函数, java会自动生成一个构造函数,如果自行定义了构造函数,Java就不会生成默认构造函数,如果想要使用默认构造函数可以显示声明。
-
构造函数可被重载。
class A { int a; int b; public A(int val_1, int val_2) { a = val_1; b = val_2 } //显示声明构造函数 public A() { } }
注意
- 任何一个类对象被生成时一定会调用该类的构造函数
- 无论一个类有多少个构造函数,生成一个类对象时一定只会调用某一个构造函数
关键字static
-
静态成员属于类的本身,而不属于对象,被类的所有对象所共有
-
即便不创建对象,也可以使用类本身的静态成员
静态成员
- 静态数据成员
- 静态方法成员
使用静态成员方法
- 类名.静态成员名
- 类的对象名.静态成员名
注意
- 在静态方法里只能直接调用同类的其他的静态成员,而不能直接访问类中的非静态成员
- 静态方法不能以任何方式引用this和super关键字
- 静态方法只能访问类的静态成员但非静态方法却可以访问类的所有成员,包括静态成员
单例设计模式
class A {
int i = 10;
private static A one = new A();
private A() {
}
static A get() {
return one;
}
}
public class Test_static {
public static void main(String args[]) {
A aa = A.get();
System.out.println(aa.i);
}
}
Java 继承
一个新类从已有的类那里获得其已有的属性和方法, 这种方式叫做继承。
这个新类叫做子类, 也叫派生类, 已有的那个类叫做父类也叫做基类
继承好处
- 代码得到极大的重用
- 形成类的层级结构体系
- 为多态创造条件
注意
- java不支持多继承,但可以使用接口进行扩展
- java不能自己继承自己
class A extends A
- 子类不能访问父类的私有成员,但内存分配上子类拥有父类私有成员内存空间
继承例子
class Box {
double width; //属性
double height;
double depth;
Box(Box ob) {
width = ob.width;
height = ob.height;
depth = ob.depth;
}
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
Box() {
width = -1;
height = -1;
depth = -1;
}
Box (double len) {
width = height = depth = len;
}
double volume() {
return width * height * depth;
}
}
class BoxWeight extends Box {
double weight;
BoxWeight (double w, double h, double d, double m) {
depth = d;
width = w;
height = h;
weight = m;
}
}
public class DemoBoxWeigth {
public static void main(String args[]) {
BoxWeight mybox1 = new BoxWeight(0, 0, 0, 34.3);
BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
double vol;
vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
System.out.println("Volume of mybox1 is " + mybox1.weight);
System.out.println();
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
System.out.println("Volume of mybox2 is " + mybox2.weight);
}
}
同包继承权限
- 子类的所有方法内部都可以访问父类除私有成员以外的所有成员,所谓子类的所有方法包括子类的私有方法。
- 通过子类对象名可以访问
- 父类除私有成员外的所有方法
- 子类的本身的除私有方法外的所有成员
- 子类可以继承父类除私有成员以外的所有方法
- 父类的私有成员不可以被子类继承,其他的成员都可以被子类继承
继承原则
如何选择继承?
B是一个A类码? 如果是则B可做A的子类
java中的类的继承其实更像是从一般到特殊的过程
父类引用变量可以引用子类对象
可以将指向继承自某个超类的子类对象引用赋值给这个超类的引用变量
class A {
private int a = 10;
void show_a() {
System.out.println(a);
}
}
class B extends A {
void hello() {
System.out.println("Hello world");
}
}
public class Test {
public static void main(String args[]) {
A demo_a = new B();
demo_a.show_a();
//error
demo_a.hello();
}
}
可以访问哪些成员是由引用变量类型决定,而不是由引用对象类型所决定
关键字super
super 关键字用法:
- 调用父类的构造函数
- 用于访问父类中被子类的某个成员隐藏的成员
使用super调用父类的构造函数
class Box {
double width; //属性
double height;
double depth;
Box(Box ob) {
width = ob.width;
height = ob.height;
depth = ob.depth;
}
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
Box() {
width = -1;
height = -1;
depth = -1;
}
Box (double len) {
width = height = depth = len;
}
double volume() {
return width * height * depth;
}
}
class BoxWeight extends Box {
double weight;
BoxWeight (double w, double h, double d, double m) {
super(w, h, d); //使用super调用父类的构造函数
weight = m;
}
}
public class DemoBoxWeigth {
public static void main(String args[]) {
BoxWeight mybox1 = new BoxWeight(0, 0, 0, 34.3);
BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
double vol;
vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
System.out.println("Volume of mybox1 is " + mybox1.weight);
System.out.println();
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
System.out.println("Volume of mybox2 is " + mybox2.weight);
}
}
用于访问父类中被子类的某个成员隐藏的成员
class A {
int i = 10;
}
class B extends A {
int i;
B(int a, int b) {
super.i = a; // i in A
i = b; // i in B
}
void show_super_i() {
System.out.println(super.i);
}
void show_i() {
System.out.println(i);
}
}
public class Test {
public static void main(String args[]) {
B demo_b = new B(1, 2);
demo_b.show_super_i();
demo_b.show_i();
}
}
创建多级继承层次
class Box {
private double width; //属性
private double height;
private double depth;
Box(Box ob) {
width = ob.width;
height = ob.height;
depth = ob.depth;
}
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
Box() {
width = -1;
height = -1;
depth = -1;
}
Box (double len) {
width = height = depth = len;
}
double volume() {
return width * height * depth;
}
}
class BoxWeight extends Box {
double weight;
BoxWeight (double w, double h, double d, double m) {
super(w, h, d); //使用super调用父类的构造函数
weight = m;
}
BoxWeight(BoxWeight ob) {
super(ob);
weight = ob.weight;
}
BoxWeight() {
super();
weight = -1;
}
BoxWeight(double len, double m) {
super(len);
weight = m;
}
}
class Shipment extends BoxWeight {
double cost;
Shipment(Shipment ob) {
super(ob);
cost = ob.cost;
}
Shipment(double w, double h, double d, double m ,double c) {
super(w, h, d, m);
cost = c;
}
Shipment(double len, double m, double c) {
super(len, m);
cost = c;
}
Shipment() {
super();
cost = -1;
}
}
public class DemoBoxWeigth {
public static void main(String args[]) {
Shipment shipment1 = new Shipment(
10, 20, 15, 10, 3.14 );
Shipment shipment2 = new Shipment(
2, 3, 4, 0.76, 1.28 );
double vol;
vol = shipment1.volume();
System.out.println("Volume of shipment is " + vol);
System.out.println("Weight of shipment is " + shipment1.weight);
System.out.println("Shipping cost: $" + shipment1.cost);
System.out.println();
vol = shipment2.volume();
System.out.println("Volume of shipment is " + vol);
System.out.println("Weight of shipment is " + shipment2.weight);
System.out.println("Shipping cost: $" + shipment2.cost);
}
}
注意
- super()总是引用最近父类的构造函数
- 如果父类构造函数需要形参,那么所有子类必需向上传递这些形参,不管子类本身是否需要形参, 都必须这么做
构造函数的执行
- 在类层次中, 从父类到子类按照继承的顺序执行构造函数。
- super() 必须是子类构造函数的第一条执行语句, 不管是否使用super()构造函数执行都是这样
- 如果没有使用super(),将执行父类的默认无参构造函数
class A {
A() {
System.out.println("class A");
}
}
class B extends A {
B() {
System.out.println("class B");
}
}
class C extends B {
C() {
System.out.println("class C");
}
}
public class Test{
public static void main(String args[]) {
C c = new C();
}
}
方法重写
在类层次中如果子类的一个方法和父类的一个方法具有相同的名称(函数名和参数列表类型)和类型签名, 那么子类方法重写了父类方法。
- 方法重写: 指在子类中重新定义父类中已有的方法
- 子类中不允许出现与父类同名同参但是不同返回值的方法,如果出现,编译报错
- 覆盖方法时,不能使用比父类中覆盖的方法更严格的访问权限
子类中不允许出现与父类同名同参但是不同返回值的方法
class A {
void print_sentence() {
System.out.println("Hello world");
}
}
class B extends A {
//error
int print_sentence() {
System.out.println("Hello world");
return 12;
}
}
public class Test {
public static void main(String args[]) {
}
}
覆盖方法时,不能使用比父类中覆盖的方法更严格的访问权限
class A {
void print_sentence() { //默认访问权限
System.out.println("Hello world");
}
}
class B extends A {
//error
private void print_sentence() { //私有访问权限
System.out.println("Hello world");
}
}
public class TestAccess {
public static void main(String args[]) {
}
}
调用父类·构造方法, 在Java中父类的构造函无法继承给子类中能使用super() 调用
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
void show() {
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {//重写了父类方法
System.out.println("K: " + k);
}
}
public class Test {
public static void main(String[] args) {
B subOb = new B(1, 2, 3);
subOb.show();
}
}
如果希望调用父类中被重写的方法, 可以使用super完成操作
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
void show() {
System.out.print("i and j: " + i + " " + j +" ");
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {//重写了父类方法
super.show(); //调用父类的show()
System.out.println("K: " + k);
}
}
public class Test {
public static void main(String[] args) {
B subOb = new B(1, 2, 3);
subOb.show();
}
}
只有当两个方法的名称和类型签名相同时才会发生重写, 否则两个方法的关系就只是重载。
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
void show() {
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
String show(String msg) {//重写了父类方法
System.out.println(msg);
return msg;
}
}
public class Test {
public static void main(String[] args) {
B subOb = new B(1, 2, 3);
subOb.show();
}
}
重写的意义 : 如果子类对继承的父类方法不满足需求就应该重写父类方法
多态
一个父类的引用类型变量它既可以指向父类的对象也可以指向子类的对象,它可以根据当前时刻指向的不同, 自动的调用不同对象的方法, 这就是多态
class A {
void print_sentence() {
System.out.println("Hello A");
}
}
class B extends A {
//error
void print_sentence() {
System.out.println("Hello B");
}
}
public class TestAccess {
public static void main(String args[]) {
/*
aa可以根据当前指向的不同对象调用相对应的
print_sentence()
*/
A aa = new B();
aa.print_sentence();
aa = new A();
aa.print_sentence();
}
}
多态注意事项:
-
子类对象可以直接赋值给父类引用, 但父类对象在任何情况下都不可以直接赋值给子类引用
-
通过父类引用只能访问子类对象从父类继承过来的成员
-
通过父类引用不能访问子类特有成员
-
父类引用永远不可能直接访问子类引用
- 只用在父类引用本身指向的就是一个子类对象时, 才可以把父类引用强制转化为子类引用
- 其他情况下不允许把父类引用强制转化为子类引用,否则运行时出错。
/* 父类引用永远不可能直接赋给子类引用 注意: 只有在父类引用本身指向的就是一个子类对象时,才可以把父类引用强制转化为子类引用 其他情况下不允许把父类引用强制转化为子类引用 */ class A { } class B extends A { } public class TestPoly_3 { public static void main(String[] args) { A aa = new A(); B bb = new B(); //bb = aa; //error //bb = (B)aa; //24行 编译没有错误,但运行时出错! 因为aa指向的是父类对象 A aa2 = new B(); //bb = aa2; //error 永远不可以把父类引用直接赋给子类引用 bb = (B)aa2; //OK 因为aa2 本身指向的就是一个B类对象 所以可以进行强制转化,注意与24行的区别 如果父类引用指向的是个子类对象,则可以通过强制类型转化把父类引用强制转化为子类引用,注意必须强制转化,在Java中无论如何绝对不可能直接把父类引用赋给子类引用的 } }
态注意事项:**
-
子类对象可以直接赋值给父类引用, 但父类对象在任何情况下都不可以直接赋值给子类引用
-
通过父类引用只能访问子类对象从父类继承过来的成员
-
通过父类引用不能访问子类特有成员
-
父类引用永远不可能直接访问子类引用
- 只用在父类引用本身指向的就是一个子类对象时, 才可以把父类引用强制转化为子类引用
- 其他情况下不允许把父类引用强制转化为子类引用,否则运行时出错。
/* 父类引用永远不可能直接赋给子类引用 注意: 只有在父类引用本身指向的就是一个子类对象时,才可以把父类引用强制转化为子类引用 其他情况下不允许把父类引用强制转化为子类引用 */ class A { } class B extends A { } public class TestPoly_3 { public static void main(String[] args) { A aa = new A(); B bb = new B(); //bb = aa; //error //bb = (B)aa; //24行 编译没有错误,但运行时出错! 因为aa指向的是父类对象 A aa2 = new B(); //bb = aa2; //error 永远不可以把父类引用直接赋给子类引用 bb = (B)aa2; //OK 因为aa2 本身指向的就是一个B类对象 所以可以进行强制转化,注意与24行的区别 如果父类引用指向的是个子类对象,则可以通过强制类型转化把父类引用强制转化为子类引用,注意必须强制转化,在Java中无论如何绝对不可能直接把父类引用赋给子类引用的 } }