面向对象的三大特征
继承(extends)
类是对对象的抽象,继承是对某一批类的对象,从而实现对现实世界更好的建模
提高代码的复用性(OOP)
extends的意思是”扩展”。子类是父类的扩展
例子(生物)
封装(encapsulation)/隐藏
多态(polymorphism)
继承(extends)
- 子类继承父类(基类、超类)的属性和方法
- 构造器不能继承!
- 实例化子类,会递归分配所有父类的空间
- 子类构造器一定调用父类构造器
- 类一定有构造器(父类、子类)
继承中的语法现象 *
Java 中继承的语法现象:
- 父类型变量可以引用子类型的实例,父类型的实现是多态的引用变量类型的自动转换(“小类型”到“大类型”的自动转换)
- 子类可以覆盖父类的方法,修改父类的行为
- 方法覆盖:子类覆盖了父类“相同方法签名”的方法
- 方法的覆盖是由方法动态绑定实现的是Java 虚拟机运行时候确定执行哪个对象哪个方法,java 最终执行子类的方法
方法的重写(override)
- 在子类中可以根据需要对从基类中继承来的方法进行重写。
- 重写方法必须和被重写方法具有相同方法名称、参数列表和返回类型。
- 重写方法不能使用比被重写更严格的访问权限
实例如下
父类
package com.neuedu.test1;
/**
* @author wqy
* @version 1.0
* @since 2019/8/8
* @apiNote 继承
* */
public class Question {
// 题号
public int id;
// 题干
public String text;
// 选项
public String[] options;
// 检查答案的方法 (父类的检查答案的 check()方法没有实际业务意义,检查答案都返回 false)
public boolean checkAnswer(String[] args) {
return false;
}
// 打印题目到控制台
public void printText() {
System.out.println("题号:"+id+"---题干----"+"text");
for(int i = 0; i<options.length;i++) {
System.out.println(options[i]);
}
}
}
子类
因为父类的 check()方法不合理(只返回 false),所以在子类中需要方法的覆盖
方法的覆盖,又叫重写(Overwrite)是根据子类的具体业务对父类方法的重写
package com.neuedu.test1;
/**
* @author wqy
* @version 1.0
* @since 2019/8/8
* @apiNote 继承
* */
public class SingleQuestion extends Question{
// 扩展功能 正确答案
String answer;
// 构建题号 题干 选项和正确答案
public SingleQuestion(int id,String text,String[] options,String answer) {
this.id = id;
this.text = text;
this.options = options;
this.answer = answer;
}
// 方法的重写
@Override
public boolean checkAnswer(String[] answers) {
//首先判断答案是否合法
if(answers == null || answers.length != 1) {
return false;
}
return this.answer.equals(answers[0]);
}
}
测试类
package com.neuedu.test1;
/**
* @author wqy
* @version 1.0
* @since 2019/8/8
* @apiNote 继承
* 测试类
* */
public class TestQuestion {
public static void main(String[] args) {
String[] options = {"爱迪生" , "爱恩斯坦", "科比", "我"};
SingleQuestion singleQuestion = new SingleQuestion(1,"世界上最好看的人是谁",options,"我");
String[] answers = {"爱迪生"};
boolean checkAnswer = singleQuestion.checkAnswer(answers);
System.out.println(checkAnswer);
}
}
继承中的构造器
子类构造器一定调用父类构造器
super()
- 子类构造器默认调用父类无参数构造器
- super()表示调用父类构造器
- 使用 super()调用父类构造器,必须写在子类构造器第一行
- this() 必须写在子类构造器第一行
- 有 super()就不能有 this(),两者互斥
解决方案:显式调用父类有参构造器
如果父类没有无参数构造器,就必须在子类中明确指定调用父类的有参数构造器
编程建议:所有的类都提供无参数构造器!减少继承时候的麻烦
static 关键字
在类中,用static声明的成员变量为静态变量,或者叫类属性,类变量
- 它为该类的公用变量,从属于类,被该类的所有实例共享,在类被加载时显示初始化;
- 对于该类的所有对象来说,static成员变量只有一份,被该类的所有对象共享!!
- 可以使用”对象.类属性”来调用。不过,一般都是用”类名.类属性”
- static变量置于方法区中
用static声明的方法为静态方法(类方法)
不需要对象,就可以调用(类名.方法名)
在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员
在普通的方法里面可以调用静态的方法和静态的属性,但是反之不能
在《Java编程思想》P86页有这样一段话:“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”
方便在没有创建对象的时候调用
public class Student{
Stirng name;
int id;
static int ss;
public static void printss(){
System.out.println(ss);
}
public void study(){
System.out.println(name+"在上课");
}
public void sayHello(String sname){
System.out.println(name+"向"+sname+"说你好!");
}
}
//新建个测试static类
public class TestStatic{
public static void main(String[] args){
Student.ss = 121;
Student.printSS();
}
}
static关键字、语句块练习
执行优先级:静态代码块 > main方法 > 构造代码块 > 构造方法
访问控制修饰符
Java 中的访问控制符,是修饰 Java 中类、属性、方法的访问可见范围的。请记住如下表格
注:
- public 修饰的,在任何地方都能访问
- protected 修饰的,在类内部、同一个包、子类中能访问
- [default]修饰的,在类内部和同一个包中可以访问,默认的,不可以写出来
- private 修饰的,仅限当前类内部访问
访问控制的原则:尽可能的封装
private 修饰的属性,仅限本类内部访问
注:
- 第 9 行,编译错误,private 修饰的属性不能在 Foo 外部调用
- 第 10 行,getA()方法是 public 的,供外界调用,间接读取了 d 的值
- 第 18 行,d 设置为 private 后,相当于只读的
[default]类内、同包下能访问,不同包不能访问
protected 修饰的,在类内部、同一个包、子类中能访问
知识点小结:
- 方法也可以用访问控制符修饰,一般为 private 的表示只在类内部调用,外部不可见
- 声明属性和方法尽可能私有。这样才能做到尽可能的封装
- 提供适当的属性访问方法,适当的开放属性的访问
- 一个源文件可以有多个类, 但是只能有一个public 类, 文件名要与public 类一致. 如果有其他类, 就只能是默认[default]修饰
- 不建议使用非公有类。就是说所有类都应该是公有的,并且一个源文件一个类.
Object类
Object类是所有Java类的父类
如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
public class Person{
}
class Person extends Object{
//可以省略不写
}
重写toString方法
- 默认返回:包名+类名+@+哈希码 ->根据对象内存位置生成唯一不重复
- 可以重写
- 打开API文档,开始熟悉
final关键字
final关键字修饰的类、变量、方法具有以下特征
- 修饰变量:常量,不能被二次赋值,只能初始化时给值或者在构造方法中给值。一般final与static同用,方便静态方法直接调用。
- 修饰方法:
该方法不可被子类重写。但是可以被重载! - 修饰类(String类):
修饰的类不能有子类,不能被继承。比如:Math、String - 修饰引用数据类型时,引用数据类型的地址不可改变,引用数据类型中的内容可以改变,修饰基本数据类型时,基本数据类型的值不可以改变。
public class TestFinal{
public static void main(String[] args){
final int MAX_VALUE = 200;//常量
}
}
//测试重载
public /*final*/ class Animal {//final修饰类则说明,这个类不能被继承
public /*final*/ void run(){//final加到方法前,一位值该方法不能被子类重写!
System.out.println("我能跑");
}
}
class Bird extends Animal{
public void run(){
System.out.println("我能飞!");
}
}
引用类型转换
向上转型(隐式/自动类型转换),是小类型到大类型的转换
向下转型(强制类型转换),是大类型到小类型
instanceof 运算符,用来检查引用对象的类型
经常与"引用类型强制转换"配合,实现安全的类型转换,避免类型转换异常
- 向上转型(隐式/自动类型转换)
- 向下转型(强制类型转换),是大类型到小类型
JavaBean规范
在 Java 中将这种建议的规范总结出一套,我们称之为“JavaBean 规范”.
关于 JavaBean 规范:JavaBean 不是语法规范,是习惯性编程规范,用这个规范写的类使用方便.
有时候 JavaBean 的类也称为:POJO 类(Plan Old Java Object)
简化规范:
- 必须有包(package)
- Java 类,具有无参数构造器
- 有用 getXxx() 和 setXxx() 声明的 Bean 属性
- 必须实现序列化接口(注:在学习 IO 的时候具体学习)
JDK 提供的类几乎都符合 JavaBean 规范。如:String 类, 集合类
JavaBean 最大的好处:使用方便
垃圾回收器GC
- 程序员无权调用垃圾回收器
- 程序员可以通过
System.gc();
通知GC运行,但是java复返并不能保证立刻运行 finalize()
方法,是java提供给程序员用来释放对象或者资源的方法,但是尽量少用。
多态
简单来说:一种事物,多种形态
所谓多态,就是指同一个方法,在调用的过程中由于对象不同可能会有不同的行为.现实生活中,同一个行为,具体实现会完全不同
具有表现多种形态的能力的特征
同一个实现接口,使用不同的实例而执行不同操作
举个例子: 打印机
父类
public class Print {
// 打印的方法
public void printer() {
System.out.println("打印。。。");
}
}
子类
public class BlackAndWhitePrinter extends Print {
@Override
public void printer() {
System.out.println("黑白打印。。");
}
}
子类
public class ColorfulPrinter extends Print {
@Override
public void printer() {
System.out.println("彩色打印。。。");
}
}
测试类
package com.neuedu.test5;
/**
* @ClassName: PrintTest
* @Description: 多态测试类
* @author wqy
* @date 2019年8月13日 上午10:55:06
*
*/
public class PrintTest {
public static void main(String[] args) {
// 黑白打印
BlackAndWhitePrinter bawp = new BlackAndWhitePrinter();
bawp.printer();
// 彩色打印
ColorfulPrinter cfp = new ColorfulPrinter();
cfp.printer();
// 多态 (实现多态的三个必要条件)
// 继承 重写 向上转型(子类转父类,用父类接收)
// 赋值多态 调用的new后边的子类的方法
Print printer = new BlackAndWhitePrinter();
printer.printer();
//传参多态
ColorfulPrinter cfp1 = new ColorfulPrinter();
toPrint(cfp1);
}
// 定义方法要打印(传参多态)
public static void toPrint(Print printer) {
printer.printer();
}
}
实现条件:
Java实现多态有三个必要条件:继承、重写、向上转型.
实现形式:
在Java中有两种形式可以实现多态。继承和接口.
多态优点:
- 简化代码
- 改善代码的组织性和可读性
- 易于扩展
封装
隐藏对象的属性和实现细节
对自己的变量私有化,提供公开的接口让别人去访问,按照提供的公共的方法来访问
通过 访问修饰符 来控制 是否要被访问
私有访问权限:private
- 使用 private 关键字来修饰成员变量。
- 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法.
公有访问权限:public
- 封装提高了数据的安全性
别人不能够通过 变量名.属性名 的方式来修改某个私有的成员属性 - 操作简单
封装后,多个调用者在使用的时候,只需调用方法即可,调用者不需要再进行判断 - 隐藏了实现
实现过程对调用者是不可见的,调用者只需调用方法即可,不知道具体实现过程