面向对象
- 2.1、this关键字
- 2.1.1、当局部变量和成员变量重名的时候可以使用this指定调用成员变量
- 2.1.2、通过this调用另一个构造方法
- 2.2、 static关键字
- 2.2.1、采用静态变量实现累加器
- 2.2.2、静态方法中访问实例变量、实例方法或this关键字
- 2.2.3、静态方法的初始化顺序
- 2.2.4、解释main方法
- 2.3、 单例模式初步
- 2.4、 类的继承
- 2.5、 方法的覆盖(Override)
- 2.5.1、对成员方法覆盖
- 2.5.2、对静态方法覆盖
- 2.6、 super关键字
- 2.6.1、调用默认构造方法
- 2.6.2、调用带参数的构造方法
- 2.6.3、采用super调用父类的方法
- 2.7、final关键字
- 2.7.1、采用final修饰的类不能被继承
- 2.7.2、采用final修饰的方法不能被覆盖
- 2.7.3、采用final修饰的变量(基本类型)不能被修改
- 2.7.4、final修饰的变量必须显示初始化
- 2.7.5、如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
2.1、this关键字
this关键字指的是当前调用的对象,如果有100个对象,将有100个this对象指向各个对象
this关键字可以使用在:
● 当局部变量和成员变量重名的时候可以使用this指定调用成员变量
● 在一个构造方法中通过this调用另一个构造方法
需要注意:this只能用在构造函数和成员方法内部,还可以应用在成员变量的声明上,static标识的方法里是不能使用this的,关于static后面再讲
2.1.1、当局部变量和成员变量重名的时候可以使用this指定调用成员变量
public class OOTest08 {
public static void main(String[] args) {
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int id) {
id = id;
}
//读取学号
public int getId() {
return id;
}
public void setName(String name) {
name = name;
}
public String getName() {
return name;
}
public void setSex(boolean sex) {
sex = sex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String address) {
address = address;
}
public String getAddress() {
return address;
}
public void setAge(int age) {
age = age;
}
public int getAge() {
return age;
}
}
输出错误,输出的都是成员变量的默认值,赋值没有起作用,这是为什么?
如:setId(int id) 方法中,我们的赋值语句为id=id,这样写Java无法知道是向成员变量id赋值,它遵循“谁近谁优先”,当然局部变量优先了,所以会忽略成员变量
【代码示例】,修正以上代码
public class OOTest09 {
public static void main(String[] args) {
Student zhangsan = new Student();
zhangsan.setId(1001);
zhangsan.setName("张三");
zhangsan.setSex(true);
zhangsan.setAddress("北京");
zhangsan.setAge(20);
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int id) {
this.id = id;
}
//读取学号
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
通过this可以取得当前调用对象,采用this明确指定了成员变量的名称,所以就不会赋值到局部变量,了解狭义和广义上的javabean的概念
2.1.2、通过this调用另一个构造方法
通过new调用当前对象的构造函数(这样是不对的)
public class OOTest10 {
public static void main(String[] args) {
//Student zhangsan = new Student(1001, "张三", true, "北京", 20);
//Student zhangsan = new Student(1001, "张三");
Student zhangsan = new Student(1002, "李四");
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Student(int id, String name) {
/*
this.id = id;
this.name = name;
this.sex=true;
this.address="北京";
this.age=20;
*/
//调用构造函数,部分值采用默认值
new Student(id, name, true, "北京", 20);
}
public Student(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
通过this调用当前对象的构造函数
public class OOTest11 {
public static void main(String[] args) {
Student zhangsan = new Student(1002, "李四");
System.out.println("id=" + zhangsan.getId());
System.out.println("name=" + zhangsan.getName());
System.out.println("sex=" + zhangsan.getSex());
System.out.println("address=" + zhangsan.getAddress());
System.out.println("age=" + zhangsan.getAge());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Student(int id, String name) {
/*
this.id = id;
this.name = name;
this.sex=true;
this.address="北京";
this.age=20;
*/
//调用构造函数,部分值采用默认值
//new Student(id, name, true, "北京", 20);
//采用this调用当前对象对象的构造函数,不能采用new,以上调用时错误的
this(id, name, true, "北京", 20);
}
public Student(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
以上输出正确
2.2、 static关键字
static修饰符可以修饰:变量、方法和代码块
● 用static修饰的变量和方法,可以采用类名直接访问
● 用static声明的代码块为静态代码块,JVM第一次使用类的时候,会执行静态代码块中的内容
2.2.1、采用静态变量实现累加器
【代码示例】
public class StaticTest01 {
public static void main(String[] args) {
Student student1 = new Student(1001, "张三", true, "北京", 20);
Student student2 = new Student(1002, "李四", true, "上海", 30);
System.out.println(student1.getCount());
System.out.println(student2.getCount());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//计数器,计算student的创建个数
private int count;
public Student(int id, String name, boolean sex, String address, int age) {
count++;
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//返回计数器
public int getCount() {
return count;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
以上输出不正确,因为采用的是成员变量作为累加器,成员变量只属于某一个对象,如果多个对象那么成员变量会有多个拷贝,对象中的成员变量都是私有的,某一个对象中的成员变量的改变不会影响到另一个对象中的成员变量的改变
【代码示例】
public class StaticTest02 {
public static void main(String[] args) {
Student student1 = new Student(1001, "张三", true, "北京", 20);
Student student2 = new Student(1002, "李四", true, "上海", 30);
System.out.println(student1.getCount());
System.out.println(student2.getCount());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//计数器,计算student的创建个数
private static int count;
public Student(int id, String name, boolean sex, String address, int age) {
count++;
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//返回计数器
public int getCount() {
return count;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
static声明的变量,所有通过该类new出的对象,都可以共享,通过该对象都可以直接访问
static声明的变量,也可以采用类直接访问,所以我们也称其为类变量
【代码示例】,采用类直接访问count
public class StaticTest03 {
public static void main(String[] args) {
Student student1 = new Student(1001, "张三", true, "北京", 20);
Student student2 = new Student(1002, "李四", true, "上海", 30);
//System.out.println(student1.getCount());
//System.out.println(student2.getCount());
System.out.println(Student.count);
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//计数器,计算student的创建个数
static int count;
public Student(int id, String name, boolean sex, String address, int age) {
count++;
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
//返回计数器
public int getCount() {
return count;
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
通过以上分析,static声明的变量会放到方法区中,static声明的变量只初始化一次,加在类的时候初始化,如果多个静态变量,会按照静态变量在类中的顺序进行初始化。
2.2.2、静态方法中访问实例变量、实例方法或this关键字
静态方法中是不能直接调用实例变量、实例方法和使用this的,也就是说和实例相关的他都不能直接调用
【示例代码】,在静态区域中调用实例方法
public class StaticTest04 {
public static void main(String[] args) {
//在静态区域中不能直接调用成员方法
//因为静态方法的执行不需要new对象
//而成员方法必须new对象后才可以执行
//所以执行静态方法的时候,对象还没有创建
//所以无法执行成员方法
method1();
}
public void method1() {
System.out.println("method1");
}
}
【代码示例】,改善以上程序,在静态区域中成功调用实例方法
public class StaticTest05 {
public static void main(String[] args) {
StaticTest05 staticTest05 = new StaticTest05();
//在静态区域中如果访问成员方法必须具有
//该成员方法对应的对象引用
staticTest05.method1();
}
public void method1() {
System.out.println("method1");
}
}
【代码示例】,改善以上程序,在静态区域中可以直接调用静态方法
public class StaticTest06 {
public static void main(String[] args) {
//可以直接调用
//method1();
//可以采用类名+方法调用
StaticTest06.method1();
}
public static void method1() {
System.out.println("method1");
}
}
【代码示例】,在静态区域中调用成员(实例)变量
public class StaticTest07 {
//private int age = 100;
private static int age = 100;
public static void main(String[] args) {
//在静态区域中无法直接访问成员变量
//System.out.println(age);
//可以采用对象的引用调用
//StaticTest07 staticTest07 = new StaticTest07();
//System.out.println(staticTest07.age);
//直接取得静态变量的值
//System.out.println(age);
//可以采用类名+属性名 访问
System.out.println(StaticTest07.age);
}
}
【代码示例】,在静态区域中使用this
public class StaticTest08 {
private int age = 100;
public static void main(String[] args) {
//因为执行main方法的时候,还没有该对象
//所以this也就不存在,无法使用
System.out.println(this.age);
}
}
2.2.3、静态方法的初始化顺序
上面已经说到,静态变量,在类加载时就会初始化,也就是将类的字节码读取到方法区时就会初始化
【代码示例】
public class StaticTest09 {
private static int age = 100;
static {
System.out.println("---------静态语句块1---------");
}
static {
System.out.println("---------静态语句块2---------");
}
static {
System.out.println("---------静态语句块3---------");
}
static {
System.out.println("---------静态语句块4---------");
System.out.println("age=" + age);
}
public static void main(String[] args) {
System.out.println("-------------main----------------");
}
}
Static声明的变量或static语句块在类加载时就会初始化,而且只初始化一次
2.2.4、解释main方法
解释main方法:
public:表示全局所有,其实就是封装性
static:静态的,也就是说它描述的方法只能通过类调用
main:系统规定的
String[] args 参数类型也是系统规定的
以上为什么是静态方法,应该很显然,这样java虚拟机调用起来会更方便,直接拿到类就可以调用main方法了,而静态的东西都在方法区中,那么你在静态方法里调用成员属性,他在方法区中无法找到,就算到堆区中查找,可能此成员属性的对象也没有创建,所以静态方法中是不能直接访问成员属性和成员方法的。
2.3、 单例模式初步
什么是设计模式:设计模式是可以重复利用的解决方案
设计模式的提出是在1995年,是由4人组作者提出的,称为GoF,也就是“四人组”
设计模式从结构上分为三类:
● 创建型
● 结构性
● 行为型
其中最简单的设计模式就是单例了,单例这种模式,尽量少用,也有将其称为“反模式”,关于缺点以后做项目时再说
单例模式有什么好处
我们知道对象实例创建完成后,会放到堆中,如果堆中的实例过多,将会存在特别多的垃圾,这样会导致一些问题,如内存溢出等,使用单例模式后,只会创建一个实例,显著减少对象实例的个数,同时也会提高性能,因为不会频繁的创建对象,这只是他的一个好处,其他方面项目中再说。
单例模式的三要素:
● 在类体中需要具有静态的私有的本类型的变量
● 构造方法必须是私有的
● 提供一个公共的静态的入口点方法
public class SingletonPatternTest01 {
public static void main(String[] args) {
//Singleton s1 = new Singleton();
//Singleton s2 = new Singleton();
//............
Singleton.getInstance().test();
}
}
class Singleton {
//静态私有的本类的成员变量
private static Singleton instance = new Singleton();
//私有的构造方法
private Singleton() {
}
//提供一个公共的静态的入口点方法
public static Singleton getInstance() {
return instance;
}
public void test() {
System.out.println("----------test----------");
}
}
2.4、 类的继承
面向对象的三大特性:
- 封装(封装细节)
- 继承
- 多态
● 继承是面向对象的重要概念,软件中的继承和现实中的继承概念是一样的
● 继承是实现软件可重用性的重要手段,如:A继承B,A就拥有了B的所有公开的特性
● java中只支持类的单继承,也就是说A只能继承B,A不能同时继承C
java中的继承使用extends 关键字,语法格式:
[修饰符] class 子类 extends 父类{
}
【代码示例】
public class ExtendsTest01 {
public static void main(String[] args) {
//如果参数比较多尽量使用setter方法,不要使用构造函数
//因为参数比较多,构造函数表达的不是很明确
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
System.out.println("id=" + student.getId());
System.out.println("name=" + student.getName());
System.out.println("sex=" + student.getSex());
System.out.println("address=" + student.getAddress());
System.out.println("age=" + student.getAge());
System.out.println("classid=" + student.getClassesId());
System.out.println("");
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
System.out.println("id=" + emp.getId());
System.out.println("name=" + emp.getName());
System.out.println("sex=" + emp.getSex());
System.out.println("address=" + emp.getAddress());
System.out.println("age=" + emp.getAge());
System.out.println("workYear=" + emp.getWorkYear());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//班级编号
private int classesId;
/*
public Student(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
*/
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
class Employee {
//员工编号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//工作年限
private int workYear;
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
}
以上输出是完全正确的,但程序上存在一些冗余,因为Student和Employee都重复出现了id,name,address,sex,age属性,而Student和Employee其实都是Person,所以应该具有person的相关属性,所以完全可以抽取出一个Person类出来,让Student和Employee继承它,这样我们的冗余代码就会减少
【代码示例】,提取Person类,让Student和Employee继承Person
public class ExtendsTest02 {
public static void main(String[] args) {
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
System.out.println("id=" + student.getId());
System.out.println("name=" + student.getName());
System.out.println("sex=" + student.getSex());
System.out.println("address=" + student.getAddress());
System.out.println("age=" + student.getAge());
System.out.println("classid=" + student.getClassesId());
System.out.println("");
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
System.out.println("id=" + emp.getId());
System.out.println("name=" + emp.getName());
System.out.println("sex=" + emp.getSex());
System.out.println("address=" + emp.getAddress());
System.out.println("age=" + emp.getAge());
System.out.println("workYear=" + emp.getWorkYear());
}
}
class Person {
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//学号
private int sid;
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
class Employee extends Person {
//编号
private int eno;
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
}
运行结果和前面的一样,先从代码数量上来看,比以前少多了,没有重复了,软件设计有一个原则“重复的代码最好不要出现两次或多次”,如果出现两次以上相同的代码,那么就不好维护了,如果要改的话,那么多处都要改,给维护带来不变,而从我们的这个示例,大家看到采用继承可以达到重用性,把父类中的所有属性都继承下来了。
注:继承是对象级别的继承,将父类对象属性、方法继承过来
静态信息是存储在方法区,可以直接通过类名调用,在对象之前创建,所以不是对象级别的,更不能被继承
2.5、 方法的覆盖(Override)
首先看一下方法重载(Overload),回顾方法重载的条件:
● 方法名称相同
● 方法参数类型、个数、顺序至少有一个不同
● 方法的返回类型可以不同,因为方法重载和返回类型没有任何关系
● 方法的修饰符可以不同,因为方法重载和修饰符没有任何关系
● 方法重载只出现在同一个类中
方法的覆盖(Override)的条件:
- 必须要有继承关系
- 覆盖只能出现在子类中,如果没有继承关系,不存在覆盖,只存在重载
- 在子类中被覆盖的方法,必须和父类中的方法完全一样,也就是方法名,返回类型、参数列表,完全一样
- 子类方法的访问权限不能小于父类方法的访问权限
- 子类方法不能抛出比父类方法更多的异常,但可以抛出父类方法异常的子异常
- 父类的静态方法不能被子类覆盖
- 父类的私有方法不能覆盖
- 覆盖是针对成员方法,而非属性
为什么需要覆盖?
就是要改变父类的行为。
2.5.1、对成员方法覆盖
【代码示例】,继承父类方法,不覆盖
public class OverrideTest01 {
public static void main(String[] args) {
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
student.printInfo();
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
emp.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
}
【代码示例】,继承父类方法,覆盖父类中的方法(改变父类的行为)
public class OverrideTest02 {
public static void main(String[] args) {
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
student.printInfo();
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
emp.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
以上子类对父类的方法进行了覆盖,改变了父类的行为,当我们new子类的时候,它不会再调用父类的方法了,而直接调用子类的方法,所以我们就完成了对父类行为的扩展。
【代码示例】,改善以上示例
public class OverrideTest03 {
public static void main(String[] args) {
//Student student = new Student();
//此种写法是错误的,Person不是Student
//Student person_student = new Person();
//此种写法是正确的,Student是Person
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
//编译出错,因为Person看不到子类Student的属性
//person_student.setClassesId(10);
person_student.printInfo();
System.out.println("");
//Employee person_emp = new Employee();
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
//编译出错,因为Person看不到子类Employee的属性
//person_emp.setWorkYear(10);
person_emp.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
【代码示例】,改善以上示例
public class OverrideTest04 {
public static void main(String[] args) {
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
print(person_student);
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
print(person_emp);
Person person = new Person();
person.setId(1003);
person.setName("王五");
person.setSex(true);
print(person);
}
private static void print(Person person) {
person.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
多态其实就是多种状态,overload(重载)是多态的一种,属于编译期绑定,也就是静态绑定(前期绑定),override是运行期间绑定(后期绑定)。
多态存在的条件:
● 有继承
● 有覆盖
● 父类指向子类的引用
2.5.2、对静态方法覆盖
【代码示例】
public class OverrideTest05 {
public static void main(String[] args) {
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
print(person_student);
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
print(person_emp);
}
private static void print(Person person) {
person.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public static void printInfo() {
System.out.println("------------Person--------------");
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public static void printInfo() {
System.out.println("------------Student------------");
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public static void printInfo() {
System.out.println("------------Employee------------");
}
}
从上面的输出可以看到,静态方法不存在多态的概念,多态和成员方法相关,静态方法只属于某一个类,声明的是那个一个类就调用的是哪一个类的静态方法和子类没有关系,不像覆盖了成员方法,new谁调谁,为什么覆盖成员方法可以构成多态(多种状态),主要是运行期的动态绑定(动态绑定构成多态),静态绑定的含义是在编译成class文件(字节码)的时候已经确定该调用哪个方法。
2.6、 super关键字
super关键字的作用:
● 调用父类的构造方法
● 调用父类的成员方法
需要注意:super只能应用在成员方法和构造方法中,不能应用在静态方法中(和this是一样的,代表父类对象),如果在构造方法中使用必须放在第一行
为什么会有super关键字?
● 因为子类必须要调用父类的构造方法,先把父类构造完成,因为子类依赖于父类,没有父,也就没有子
● 有时需要在子类中显示的调用父类的成员方法
那么我们以前为什么没有看到super,而且我们也有继承,如:Student继承了Person?
● 因为子类中我们没有显示的调用构造方法,那么他会默认调用父类的无参构造方法,此种情况下如果父类中没有无参构造方法,那么编译时将会失败
注意构造方法不存在覆盖的概念,构造方法可以重载
2.6.1、调用默认构造方法
public class SuperTest01 {
public static void main(String[] args) {
Person student = new Student();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Person() {
//System.out.println(this);
System.out.println("----------Person-----------");
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public Student() {
//System.out.println(this);
//显示调用父类的构造方法
//调用父类的无参的构造函数
//super();
System.out.println("--------Student----------");
//编译错误,必须将super放到构造函数的第一语句
//必须先创建父类,才能创建子类
//super();
}
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
关于构造方法的执行顺序,先执行父类的再执行子类的,必须完成父类的所有初始化,才能创建子类
2.6.2、调用带参数的构造方法
public class SuperTest02 {
public static void main(String[] args) {
/*
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
*/
//编译出错,因为Person看不到子类Student的属性
//person_student.setClassesId(10);
/*
person_student.printInfo();
System.out.println("");
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
*/
//编译出错,因为Person看不到子类Employee的属性
//person_emp.setWorkYear(10);
//person_emp.printInfo();
Person person_student = new Student(1001, "张三", true, "北京", 20, 10);
person_student.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Person() {
System.out.println("--------------Person-------------");
}
public Person(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age= age;
}
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public Student(int id, String name, boolean sex, String address, int age, int classesId) {
/*
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age= age;
this.classesId = id;
*/
/*
setId(id);
setName(name);
setSex(sex);
setAddress(address);
setAge(age);
this.classesId = classesId;
*/
//手动调用调用带参数的构造函数
super(id, name, sex, address, age);
this.classesId = classesId;
}
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
2.6.3、采用super调用父类的方法
public class SuperTest03 {
public static void main(String[] args) {
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
print(person_student);
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
print(person_emp);
}
private static void print(Person person) {
person.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
//System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
//采用super调用父类的方法
super.printInfo();
System.out.println("classesId=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
//System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
System.out.println("workYear=" + workYear);
//采用super调用父类的方法
super.printInfo();
}
}
2.7、final关键字
final表示不可改变的含义
● 采用final修饰的类不能被继承
● 采用final修饰的方法不能被覆盖
● 采用final修饰的变量不能被修改
● final修饰的变量必须显示初始化
● 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
● 构造方法不能被final修饰
● 会影响JAVA类的初始化:final定义的静态常量调用时不会执行java的类初始化方法,也就是说不会执行static代码块等相关语句,这是由java虚拟机规定的。我们不需要了解的很深,有个概念就可以了。
2.7.1、采用final修饰的类不能被继承
public class FinalTest01 {
public static void main(String[] args) {
}
}
final class A1 {
public void test1() {
}
}
//不能继承A1,因为A1采用final修饰了
class B1 extends A1 {
public void test2() {
}
}
2.7.2、采用final修饰的方法不能被覆盖
public class FinalTest02 {
public static void main(String[] args) {
}
}
class A1 {
public final void test1() {
}
}
class B1 extends A1 {
//覆盖父类的方法,改变其行为
//因为父类的方法是final修饰的,所以不能覆盖
public void test1() {
}
public void test2() {
}
}
2.7.3、采用final修饰的变量(基本类型)不能被修改
public class FinalTest03 {
private static final long CARD_NO = 878778878787878L;
public static void main(String[] args) {
//不能进行修改,因为CARD_NO采用final修改了
CARD_NO = 99999999999999L;
}
}
2.7.4、final修饰的变量必须显示初始化
public class FinalTest04 {
//如果是final修饰的变量必须初始化
private static final long CARD_NO = 0L;
public static void main(String[] args) {
int i;
//局部变量必须初始化
//如果不使用可以不初始化
System.out.println(i);
}
}
2.7.5、如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
public class FinalTest05 {
public static void main(String[] args) {
Person p1 = new Person();
//可以赋值
p1.name = "张三";
System.out.println(p1.name);
final Person p2 = new Person();
p2.name = "李四";
System.out.println(p2.name);
//不能编译通过
//p2采用final修饰,主要限制了p2指向堆区中的地址不能修改(也就是p2只能指向一个对象)
//p2指向的对象的属性是可以修改的
p2 = new Person();
}
}
class Person {
String name;
}