面向对象三
抽象类
特点
抽象类不能创建对象,其他功能与正常类相同,可以有成员变量、成员方法、构造方法;
主要就是在上层定义功能,让子类继承;
一个子类一旦继承抽象类,要么重写所有抽象方法,要么该类也定义为抽象类;
抽象类只能作为父类;
抽象方法
抽象方法是一种特殊的方法,它只有声明,没有具体的实现;
抽象方法必须用abstract关键字修饰;
为什么有
在一些体系结构的顶端类中,有些功能没有必要实现,因为子类中所需的功能都不同,这是就可以使用抽象方法;
//方法重写
public class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
}
//定义抽象类
public abstract class Cat extends Animal{
}
/*
抽象类:
使用abstract修饰的类是抽象类
如果以一个类有抽象方法,则其必是抽象类
一个抽象类不一定有抽象方法
*/
public abstract class Animal {
private String name;
private int age;
public Animal(){
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
/*
抽象方法,没有代码块,使用abstract修饰
只是定义了eat方法,没有具体实现
*/
public abstract void eat();
}
public class Animal_Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
}
}
面向对象语言的三大特征(前两个)
封装
一般意义-->将重复出现的代码抽取成一个函数,成为代码的封装(包装);
面向对象中实际意义-->(通过访问权限修饰符)将类的某些信息隐藏的类内部,不让外部直接访问操作,而用改类提供的方法来进行访问操作;
优点
方便修改实现;
隐藏类的信息;
方便加入控制语句;
在其他类需通过特定方法访问;
案例1:
将类中成员变量私有化
public class packaging_test {
private String name;
private int age;
//外部通过构造方法来访问成员变量
//不实用,不灵活
//不建议使用
// public packaging_test(){
// if (name.length() > 2 && name.length() < 6){
// this.name = name;
// }
// if (age>=0&&age<150){
// this.age = age;
// }
// }
//向外提供一个公共的方法访问,可在此方法加入限制语句
public void setName(String name){
if (name.length() > 2 && name.length() < 6){
this.name = name;
}
}
public String getName(){
return this.name;
}
public void setAge(int age){
if (age>=0&&age<150){
this.age = age;
}
}
public int getAge(){
return this.age;
}
}
public class person_test {
public static void main(String[] args) {
packaging_test person = new packaging_test();
//如果类中属性权限开放,其他类直接访问操作,则无法控制赋值
//person.name = "@#$";
//设置权限
//person.name;报错
//通过类方法进行访问
person.setName("ctvybh");
System.out.println(person.getName());
person.setAge(25);
System.out.println(person.getAge());
}
}
案例2:
将类中成员方法私有化
public class packaging_method {
static packaging_method window = new packaging_method();
//将构造方法私有化,让外界无法调用
private packaging_method(){
}
public static packaging_method getWindow(){
return window;
}
}
public class window {
public static void main(String[] args) {
System.out.println(packaging_method.getWindow());
}
}
继承
多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类(父类),则其余类(子类)无需在定义,当需要使用时,只需要与抽取出来的类构成继承关系即可;
优点
减少了代码冗余,实现了代码的复用性;
增强了程序的扩展性,子类可在自身中扩展自己特有的功能,而不影响其他类;
类与类之间产生了“is-a”(什么是什么)的关系,为多态的使用提供了前提
时机
当类与类符合”is-a“关系时;
语法
通过extends关键字,可以声明一个类B继承类A所有的全部属性和行为,其意义是表示子类是对父类的扩展 ;
特点
子类会继承父类所有的实例变量和实例方法 ;
子类不能直接访问父类中私有的的成员变量和方法 ;
Java支持多层继承(继承体系),展示继承的传递性 ;
一个父类可以同时拥有多个子类 ;
Java只支持单继承,不支持多重继承;
//当一个类没有显示继承,那么这个类默认继承Object类;
//类java.lang.Object是Java体系中最大的类,是类层次结构的根类,是其他所有类的父类,在其上没有其余的类,每个类都使用Object作为超类;
[修饰符] class 类A (extends Obiect){
...
}
//一个类只能直接继承一个类(间接可继承多个),继承的传递性;
[修饰符] class 类B extends 类A {
...
}
例:猫和狗都是动物-->抽取一个动物类-->让猫和狗继承动物类;
//狗类
public class Dog extends Animal{
public void lookHome() {
System.out.println("看家");
}
}
//猫类
public class Cat extends Animal{
public void catchMouse(){
System.out.println("抓老鼠");
}
}
//哮天犬-->进行间接继承,以展示继承的传递性;
public class Xiao_Tian_Quan extends Dog{
public void fly(){
System.out.println("飞");
}
}
//动物类
public class Animal {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃东西");
}
}
//测试类
public class Animal_test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("🔪哥");
dog.setAge(3);
System.out.print(dog.getAge() + "岁的");
System.out.print(dog.getName());
dog.lookHome();
Cat cat = new Cat();
cat.setName("喵桑");
cat.setAge(4);
System.out.print(cat.getAge() + "岁的");
System.out.print(cat.getName());
cat.catchMouse();
Xiao_Tian_Quan XTQ = new Xiao_Tian_Quan();
XTQ.setName("哮天犬");
XTQ.setAge(1500);
System.out.print(XTQ.getAge() + "岁的");
System.out.print(XTQ.getName());
XTQ.fly();
}
}
方法的重写(Override)
当父类中方法的实现无法满足子类的需求时,此时可以在子类中对父类的方法进行重写(也称覆盖),再此调用时会使用子类重写后的方法;
要求
子类中重写方法的结构必须要与父类中方法的结构一致;
方法名、参数列表、 返回值必须一致;
重写的方法访问权限也应等于或大于父类方法权限;
子类方法抛出的异常不能大于父类被重写方法的异常;
在子类中进行方法的重写时,将“@Override”标识符定义在重写的方法上面-->用来检测格式是否符合要求,在阅读代码时明确知道此方法重写的;(也可不添加,只要保证重写的方法结构与父类方法结构一致即可)
注意
构造方法、静态方法不能重写;
成员变量不存在重写;
父类私有方法不能重写;
跨包的父类默认权限方法也不能重写;
//子类
public class Dog extends Animal{
public void lookHome() {
System.out.println("看家");
}
@Override
public void eat(){
System.out.println("吃骨头");
}
}
//父类
public class Animal {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃东西");
}
}
//测试类
public class Animal_test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("🔪哥");
dog.setAge(3);
System.out.print(dog.getAge() + "岁的");
System.out.print(dog.getName());
dog.eat();
}
}
super
作用
在Java类中使用super来调用父类中的指定操作;
super可用于访问父类中定义的属性 ;
super可用于调用父类中定义的成员方法 ;
super可用于在子类构造方法中调用父类的构造方法;
注意
super和this用法相似,注意区分-->super代表父类的内存标识,this表示本类对象的引用;
不要把super误认为父类对象,在创建子类对象时,父类不会创建对象,只会将父类中的信息载入值子类对象中;
//狗类
public class Dog extends Animal{
public void lookHome() {
super.eat();
System.out.println("看家");
}
@Override
public void eat(){
System.out.println("吃骨头");
}
}
//动物类
public class Animal {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃东西");
}
}
//测试类
public class Animal_test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setName("🔪哥");
dog.setAge(3);
dog.lookHome();
}
}
继承中的构造方法
在创建子类对象时,必须先在子类构造方法的第一行调用父类的构造方法;(规定super(形参列表),必须声明在构造器的首行)
子类继承父类时,不会继承父类的构造方法。只能通过“super(形参列表)” 的方式调用父类指定的构造方法;
如果在子类构造器的首行没有显示调用super(形参列表),则子类此构造器 默认调用super(),即调用父类中空参的构造器;
这么做是为了保证先对父类成员进行初始化;
public class Dog extends Animal{
public Dog(){
super();
System.out.println("Dog的构造方法");
}
//有参构造
public Dog(String name,int age){
super(name,age);
}
}
public class Animal {
private String name;
private int age;
public Animal(){
System.out.println("Animal的构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(){
System.out.println("吃东西");
}
}
public class Animal_test {
public static void main(String[] args) {
Dog dog = new Dog("🔪哥",3);
}
}
成员变量和局部变量
数据类型
基本类型变量:byte、short、int、long、float、double、char、boolean(八种关键字);
引用类型变量:类、数组、持有的是对象的地址;
成员变量
位置分类:类中定义-->成员变量;
权限:可使用权限修饰符;
初始化:在构造方法中系统自动赋初值;
生命周期:随着对象的创建而存在,对象销毁而销毁(非静态);
随着类加载而存在,类销毁而销毁(静态);
内存位置:在堆内存(非静态);方法区(静态);
局部变量
方法中定义-->局部变量;
权限:不可使用权限修饰符;
初始化:必须手动赋初值;
生命周期: 随着方法的调用而存在,方法结束销毁;
内存位置:在栈内存;