一、类的继承
1.继承的概念:
继承机制是面向对象程序设计不可缺少的关键概念,是实现代码可重用的根基,是提高软件系统的可拓展性与可维护性的主要途径。
所谓继承是指一个类的定义可以基于另外一个已经存在的类,即子类基于父类,从而实现父类代码的重用,子类能吸收已有类的属性和行为,并能拓展新的能力。
2.继承的形式:
在java程序中,如果想声明一个类继承另一个类,需要使用extends关键字:
【访问权限修饰符】【修饰符】子类名 extends 父类名{子类体}
例子:
/*
* 定义Persion类
*/
class Persion{
// 定义name属性
String name;
// 定义Persion类的work方法
public void work() {
System.out.println("尽心尽力地工作");
}
}
//定义学生类Student 继承 Persion类
class Student extends Persion {
// 定义一个打印name的方法
public void printName() {
System.out.println("name=" + name);
}
}
/*
* 定义测试类
*/
public class Demo1 {
public static void main(String[] args) {
Student student = new Student();
student.name = "小明"; // 为该学生类的name属性进行赋值
student.printName(); // 调用该学生类的printName()方法
student.work(); // 调用Persion类继承来的work()方法
}
}
3.继承的注意事项:
在Java中,类只支持单继承,也就是说一个类只能有一个直接父类。
例如下面这种情况是不合法的。
class A{}
class B{}
class C
extends
A,B { } // C类不可以同时继承A类和B类
但是多个类可以继承一个父类
例如下面这种情况是允许的。
class A{}
class B
extends
A{}
class C
extends
A{} // 类B和类C都可以继承类A
在Java中,
多层继承是可以的
,即一个类的父类可以再去继承另外的父类。
例如C类继承自B类,而B类又可以去继承A类,这时,C类也可称作A类的子类。下面这种情况是允许的。
class A{}
class B
extends
A{} //
类B继承类A,类B是类A的子类
class C
extends
B{} //
类C继承类B,类C是类B的子类,同时也是类A的子类
在Java中,
子类和父类是一种相对概念
,也就是说一个类是某个类的父类的同时,也可以是另一个类的子类。例如上面的这种情况中,
B类
是A类的子类,同时又是C类的父类。
class A{}
class
B
extends
A{} // 类B继承类A,类B是类A的子类
class C
extends
B
{} // 类C继承类B,类C是类B的子类,同时也是类A的子类
4.子父类中成员变量的特点:
如果
子类
中出现了
父类
中
同名的成员变量
,这时子类中若要访问父类中的成员变量,必须使用
关键字
super来完成
。super用来表示当前对象中包含的父类对象空间的引用:
例子:
class Father {
//Father中的成员变量。
int num = 5;
}
class Son extends Father
{
//Son中的成员变量
int num = 6;
public void show(){
//子父类中出现了同名的成员变量时
//在子类中需要访问父类中非私有成员变量时,需要使用super关键字
//访问父类中的num
System.out.println("Father num="+super.num);
//访问子类中的num2
System.out.println("Son num2="+this.num);
}
}
// 在测试类中
class Demo2{
public static void main(String[] args){
Son son = new Son(); //创建子类对象
son.show(); //调用子类中的show方法
}
}
5.子父类中成员方法的特点:
当在程序中通过对象调用方法时,
会先在
子类
中查找有没有对应的方法
,若子类中存在就会执行子类中的
方法,若子类中不存在就会执行父类中相应的方法。
例子:
class Persion3{
String name; // 定义name属性
// 定义Persion类的work方法
public void work() {
System.out.println("尽心尽力地工作");
}
public void display(){
System.out.println("这是一个Persion类");
}
}
/*
* 定义学生类Student 继承 Persion类
*/
class Student3 extends Persion3 {
// 定义一个打印name的方法
public void display(){
System.out.println("这是一个Student类");
}
}
public class Demo3 {
public static void main(String[] args) {
Student3 student3=new Student3();
student3.display();
student3.work();
}
}
6.子父类中构造方法的特点:
在创建子类对象时,
因为子类
继承
父类的
成员变量
和
成员方法
,所以
子类会先加载父类
,调用
父类的构造
方法
。因此
子类
中
所有构造方法
的
第一行
有
默认的隐式super()语句来调用父类的构造方法
。如果当父类
中
没有空参数构造方法
时,子类的
构造方法必须有显示的super语句
,
指定要访问父类有参数的构造方法
。
例子:
class Persion5{
String name; // 定义name属性
int age;
public Persion5(String name, int age){
this.name=name;
this.age=age;
}
}
/*
* 定义学生类Student 继承 Persion类
*/
class Student5 extends Persion5 {
// 定义一个打印name的方法
public Student5(String name,int age){
super(name,age);
}
public void printInfo(){
System.out.println("name="+name+",age="+age);
}
}
public class Demo5 {
public static void main(String[] args) {
Student5 student5=new Student5("张三",20);
student5.printInfo();
}
}
二、抽象类
1.概念
在一个类中,
含有的方法只有方法名
,
没有方法体的类
,我们称之为
抽象类
。
2.抽象方法定义的格式:
public
abstract
返回值类型 方法名(参数)
;
3.
抽象类定义的格式:
public abstract class 类名 {
语句
}
public abstract class Teacher{
//抽象函数。需要abstract修饰,分号;结束
public abstract void work();
}
4.使用抽象类要注意的点
子类继承了父类的方法,而父类的方法是抽象的,并没有具体的实现过程,那就需要子类(
普通类
)
实现父类的抽象方法,即:撰写具体的实现。如果子类不实现该方法,那么子类就得是
抽象类
5.抽象类的特点总结
抽象类由关键字
abstract
来修饰;
抽象方法也有关键字
abstract
来修饰,且
没有方法体
,
连大括号都没有
;
抽象类可以
含有抽象方法,也可以含有普通方法,也可以任何方法都不含
;
抽象类
不能直接创建对象
(建自己的对象),因为抽象类中含有了抽象方法
后,使用对象的引用去调用是没有任何意义的;
抽象类是
可以通过多态的形式,建立子类对象的,这种方式叫做:向上造型
;
抽象类也是类,
类与类之间就可以形成继承关系
,
当一个普通类继承了抽象
类后,就需要实现抽象类的全部抽象方法,即重写;否则,当前的普通类也得
是一
个抽象类,只继承不实现是不被允许的。
6.抽象类的意义:
我们都知道,子类共有的属性和方法,我们会抽出来,放在一个专门的类中
进行存储,这样所有子类就不需要在各自类中写相同的内容,直接通过继承该
类就能
自动拥有
,提高了代码的可重用性,提升了开发效率,那这样存放共有
属性和方法的类,我们称之为父类(也称为超类或者基类)。
而
自动拥有
,意味着多个子类对所继承下来的行为实现过程都是父类的那一
套,都是一样的,这样就不能体现子类个性化的特征,因此
Java
允许子类对继承
父类的方法进行
重写
,重写后该方法还是父类中声明的共有方法,但实现过程
就已经是子类个性化的实现了,符合了多样性。但是这个重写又不是必须的,
需要子类主动进行重写。这样就存在一个问题是不主动重写的话,还是无法满
足多样性的体现,此时,就有了
抽象类
,抽象类中,对这类要求
子类共有,且
要体现多样性的方法只进行声明,不进行具体实现
,
而实现这个操作就让继承
的子类必须进行个性化实现
,也就是必须进行重写,这样就很好的解决了某些
行为在一定场景下必须要多样性的需求。
7.abstract关键字的冲突:
final
:
被 abstract
修饰的方法,强制要求子类重写,被
final
修饰的方法子类不能重写
private
:
被 abstract
修饰的方法,强制要求子类重写,被
private
修饰的方法子类不能重写
static
:
被 static
修饰的方法可以类名调用,类名调用抽象方法没有意义
三、接口和类的高级特性
1.
static修饰符:
static
是
静态
的意思,可以修饰成员变量,也可以修饰成员方法。
public class Student {
String name;
int age;
//采用static修饰成员变量,称之为静态变量
static String schoolName;
//采用static修饰成员方法,称之为静态方法
}
public static void showScoreInfo() {
System.out.println(schoolName + "的所有的学生学完40学分才能毕业!");
}
}
public class Demo1 {
public static void main(String[] args) {
//通过类名.成员变量访问静态变量
Student.schoolName="电子科技大学";
System.out.println(Student.schoolName);
//通过类名.方法名访问静态方法
Student.showScoreInfo();
}
}
例子:
class User {
String name;
int age;
static int onLineNumber;
}
public class StaticTest1 {
public static void main(String[] args) {
User.onLineNumber++;
User u1 = new User();
u1.name = "张三";
u1.age = 23;
sout(u1.name + "---" + u1.age
+ "---" + u1.onLineNumber);
User.onLineNumber++;
User u2 = new User();
u2.name = "李四";
u2.age = 24;
sout(u2.name + "---" + u2.age
+ "---" + u2.onLineNumber);
}
}
2.static的特点:
static 修饰成员的特点
被其修饰的成员, 被该类的所有对象所共享
多了一种调用方式, 可以通过类名调用
随着类的加载而加载, 优先于对象存在
static 成员变量
共享数据
static 成员方法
常用于工具类
3.final关键字:
final
关键字意思是
最终,不可变的
,可以修饰(方法,类,变量)
final
修饰的特点
修饰方法:表明该方法是最终方法,
不能被重写
修饰类:表明该类是最终类,
不能被继承
修饰变量:表明该变量是常量,
不能再次被赋值
通常使用public static final
修饰的变量来完成定义。此时
变量名用全部大写
,
多个单词使用下划线连接
4.final的特点:
1
)
final
修饰类不可以被继承,但是可以继承其他类
,伪代码如下:
class Grandfather {
}
final class Father extends Grandfather {
//可以继承Grandfather类
}
class Son extends Father{
//不能继承Father类
}
2)
final
修饰的方法不可以被覆盖
,
但父类中没有被
final
修饰方法,子类覆盖后
可以加
final
,
伪代码如下:
class Father {
// final修饰的方法,不可以被覆盖,但可以继承使用
public final void method1(){
}
public void method2(){
}
}
class Son extends Father {
//只能重写method2方法
public final void method2(){
}
}
3)final修饰的变量称为常量,这些变量只能赋值一次
4)
引用类型的变量值为对象地址值,地址值不能更改,但是地址内的对象属性值
可以修改
,伪代码如下:
final Person p1 = new Person();
Person p2 = new Person();
p1 = p2; //final修饰的变量p,所记录的地址值不能改变
p1.name = "李四";//可以更改p对象中name属性值
p1.age= 24;//可以更改p对象中age属性值
p1不能为别的对象,而p1对象中的name或age属性值可更改。
5)
修饰成员变量,需要在创建对象前赋值,否则报错
。
没有显式赋值时,当有多个构造方法的均需要为其赋值,
伪代码如下:
class Demo {
//直接赋值
final int num1= 100;
//final修饰的成员变量,需要在创建对象前赋值,否则报错。
final int num2;
public Demo(){
//可以在创建对象时所调用的构造方法中,为变量num2赋值
Num2 = 2016;
}
}
6)
在
java
程序开发中,我们想在类中定义一个静态常量,
通常使用
public static final
修饰的变量来完成定义
。此时变量名用全部大写,
多个单词使用下划线连接
7)需要注意的是:
接口中的每个成员变量都默认使用 public static final
修饰
。所有接口中的成员变量已是静态常量,由于接口没有构造方法
,所以必须显示赋值。可以直接用接口名访问。
5.接口:
1)概念:
接口:体现的思想是对规则的声明
Java中的接口更多体现的是
对行为的抽象
。
2)形式:
接口用关键字
interface
来定义:
public
interface 接口名 {}
3)接口
不能实例化,且接口没有构造方法
4)接口和类之间是
实现
关系,通过
implements
关键字表示
public class 类名
implements
接口名
{}
5)接口的子类(实现类)要么重写接口中的所有抽象方法,要么是抽象类
6)接口中的成员特点:
成员变量:只能是常量
默认修饰符:
public static final
构造方法:没有
成员方法:只能是抽象方法
默认修饰符:
public abstract
关于接口中的方法,JDK8
和
JDK9
中有一些新特性
四、代码块:
class Student {
static String school;
static {
school = "阳光学院";
System.out.println("Student类的静态代码块");
} //静态代码块
{
System.out.println("Student类的构造代码块");
System.out.println("好好学习,天天向上。");
} //构造代码块
public Student(){
System.out.println("空参构造方法...");
} //构造代码块
public Student(int num){
System.out.println("带参构造方法...");
} //构造方法
}
1)概念:
在Java类下,使用 { } 括起来的代码被称为代码块
2)分类:
构造代码块
位置:类中方法外定义
特点:每次构造方法执行的时,都会执行该代码块中的代码,
并且在构造方法执行前执行
作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
静态代码块
位置:类中方法外定义
特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化的操作
局部代码块
位置:方法中定义
作用:限定变量的生命周期,及早释放,提高内存利用率
五、匿名对象
概念:匿名对象是指创建对象时,
只有创建对象的语句,却没有把对象地址值赋值给某个变量
。
匿名对象的使用,有如下几种方式:
创建匿名对象直接使用,没有变量名,只能使用一次。
new Person().eat() //eat方法被一个没有名字的Person对象调用了
。
匿名对象可以作为
方法接收的参数
、
方法返回值
使用
例子:
class Person2 {
private String name;
private int age;
}
class Tools {
public static Person2 getPerson(){
//匿名对象作为方法返回值
return new Person2();
}
public static void method(Person2 p){}
}
class Demo4 {
public static void main(String[] args) {
//调用getPerson方法,得到一个Person对象
Person2 person =Tools.getPerson();
//调用method方法
Tools.method(person);
//匿名对象作为方法接收的参数
Tools.method(new Person2());
}
}