Java教程

面向对象编程(包+继承)

本文主要是介绍面向对象编程(包+继承),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • 一、包
    • 1.包的概述
    • 2.使用系统包
    • 3.重复包的使用
    • 4.导入静态包(不建议)
    • 5.常用的系统
  • 二、继承(extends)
    • 1.继承初理解
    • 2.继承的好处
    • 3.private修饰参数
    • 4.(面试问题)子类继承了父类那些东西?
    • 5.super关键字
    • 6.代码的执行顺序
    • 7.复杂的继承关系
    • 8.继承的注意事项
    • 9.继承时,相同名属性的分布
  • 三、访问修饰限定符
  • 四、final:
  • 五、组合
  • 六、多态
    • 1.向上转型
    • 2.向下转型
    • 3.重写
    • 4.理解多态
  • 七、抽象类
  • 八、接口
    • 1.接口的细节
    • 2.Comparable接口
    • 3.比较器(Comparator)
    • 3.Cloneable接口


一、包

1.包的概述

包是组织类的方式,使用包的主要目的是保证类的唯一性。
路径不同,则就是唯一的,例如:同事与你写了一个同样名字的类,就会导致冲突,导致编译无法通过
包其实是一个文件夹
在这里插入图片描述

2.使用系统包

1.使用导入包的方式来使用系统包
在java文件夹中有这样一个文件(一般为压缩文件,这是解压后文件),储存着java的源代码中的包

像这种头文件叫做导入包
在这里插入图片描述
使用*的时候,导入所有的包(你使用那个包时自动导入)
2.不使用系统包的方式来导入包
例:
在这里插入图片描述
使用这种方式来进行导入,标明好路径。

3.重复包的使用

import java.util.*;
import java.sql.*;

在这两个包中同时拥有Date这个类,会导致歧义,以至于编译器无法识别,在这种情况下,就不能使用导入系统包的方式来进行,而必须写完整的类名
在这里插入图片描述

4.导入静态包(不建议)

import static java.lang.System.*;

这种导入是静态导入导入这种包后,常使用的打印函数就可以这样写

out.println("haha");

5.常用的系统

import java.lang.*;//系统常用的基础类(String、Object),此包从JDK1.1后自动导入。
import java.lang.reflect.*;//反射编程包;
import java.net.*;//进行网络编程的开发包
import java.sql.*;//进行数据库编程的开发包
import java.util.*;//是java提供的工具程序包。(集合类等)
import java.io.*;//I/O编程开发包。

二、继承(extends)

1.继承初理解

在编写类时,可能会有很多相同的属性及方法。
例:

class dog{
    public String name;
    public int age;
    public void eat(){
        System.out.println("chi()");
    }
    public void crow(){
        System.out.println("wangwang");
    }
}
class cat{
    public String name;
    public int age;
    public void eat(){
        System.out.println("chi()");
    }
    public void fly(){
        System.out.println("fly()");
    }
}

这时候就可以使用继承,把相同的属性或方法包装起来,其他类来继承

class animal{
    public String name;
    public int age;
    public void eat(){
        System.out.println("chi()");
    }
}
class dog extends animal{
    
    public void crow(){
        System.out.println("wangwang");
    }
}
class bird extends animal{
    public void fly(){
        System.out.println("fly()");
    }
}

在上述例子中:
dog类extends了animal
这时
dog:子类 、 派生类
animal:父类、基类、超类

2.继承的好处

可以进行代码的复用。

3.private修饰参数

若父类方法中有参数或方法是被private修饰,则使用时不能进行使用。

class animal{
    private String name;
    public int age;
    public void eat(){
        System.out.println("chi()");
    }
}
public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println(dog.name+"hh");
    }

此时调用时则会进行报错。

4.(面试问题)子类继承了父类那些东西?

答:除构造方法之外的所有都被继承了。

5.super关键字

子类的构造需要先帮助父类对象进行构造(调用父类的构造方法)。

class Animal{
    private String name;
    public int age;
    public void eat(){
        System.out.println("chi()");
    }
    public Animal(String name){
        this.name=name;
    }
}
class Dog extends Animal{
	public String sex;
    public Dog(String name,String sex){
        super(name);  //注:用super来给父类构造时要放到第一行,否则会报错。
        this.sex=sex;
    }
    public void crow(String name){
       System.out.println("wangwang");
    }
}

否则程序会进行报错。
super的三种使用方式:

  1. super():调用父类的构造方法(必须放到第一行)
  2. super.data:调用父类的成员属性
  3. super.func:调用父类的成员方法

6.代码的执行顺序

  1. 父类的static{}
  2. 子类的static{}
  3. 父类的实例代码块{}
  4. 父类的构造函数
  5. 子类的实例代码块{}
  6. 子类的构造函数
    静态的一定先执行,只执行一次。

7.复杂的继承关系

class A{ 
}
class B extends A{
}
class C extends B{
}
class D extends C{
}

注:这种继承关系最多不要超过三层,若不想被继承需要使用final来修饰来防止不被继承。

8.继承的注意事项

  1. 使用extends
  2. Java中一个子类,只能继承一个父类
  3. 子类会继承父类的所有public的字段和方法
  4. 对于父类的private方法和字段,子类是无法访问的(并不是无法继承)

9.继承时,相同名属性的分布

class A{
    public int a = 1;
}
class B extends A{
    public int a = 2;
    public int b = 3;
}
public class testw {
    public static void main(String[] args) {
        B b = new B();
        System.out.println(b.a);
    }
}

这种时候的调用a时,会调用子类的a,而不会调用父类的a。

三、访问修饰限定符

在这里插入图片描述

public :公共权限
所有的文件都可以进行访问

private,:私有权限
只有在当前类中可以进行访问

protected:受保护权限
在继承时使用,在父类中有protected的属性或方法在不同包中子类继承父类时可以进行调用,使用super关键字进行调用

default:默认包访问权限
只能在当前包中进行访问

四、final:

  1. final来修饰常量,int a = 10;
  2. final来修饰类,final class A {},这个类叫做密封类,不想被继承时使用。
  3. final来修饰方法,这个方法叫做密封方法。

五、组合

像下面这种关系就叫组合

class Student{ //类
}
class teacher{ //类
}
class school{
    public Student[] student;
    public teacher[] teacher;
}

六、多态

字面意思:一种事物多种形态

1.向上转型

子类对象给父类

Animal animal = new Dog("张三");

注意问题:
在Dog子类对象中创建 变量a;
在Animal父类中创建 变量b;

        Animal animal = new Dog("张三");
        System.out.println(animal.b);
        System.out.println(animal.a);  //报错,父类对象无法调用子类对象
        Dog dog = new Dog("李四");
        System.out.println(dog.b);
        System.out.println(dog.a);

此时animal的类型是Animal,所以只能访问Animal类自己的成员。

向上转型的三个时机:

  1. 直接赋值:
Animal animal = new Dog("张三");
  1. 传值:
public static void main(String[] args) {     
	func(animal);  //这三种发生向上转型
	func(dog);
	func(new Dog("王五"));
}
public static void func(Animal animal){

}
  1. 返回值:
public static void main(String[] args) {    
	Animal animal1 = func1();
}
public static Animal func1(){
	Dog dog = new Dog("张三");
	return dog;
}

2.向下转型

父类对象给子类

    public static void main(String[] args) {
        Animal animal = new Dog("张三");
        Dog dog = (Dog) animal;
        dog.crow();
    }

注意事项:

public static void main(String[] args) {
            Animal animal = new Animal("张三");
            Dog dog = (Dog) animal;
            dog.crow();
        }

此时代码会进行报错,回报一个类型转换错误
所以说向下转型,必须要进行向上转型。
避免错修改:

			//判断一下animal 是不是 Dog 的实例。
			if(animal instanceof Dog){
                Dog dog = (Dog) animal;
                dog.crow();
            }

如果animal引用了Dog则返回true,否则false。
这样就安全了。

3.重写

class Animal{
	public void eat(){
        System.out.println("chi()");
    }
}
class Dog extends Animal{
	@Override //注解:标识在这里发生了重写
	public void eat() {
        System.out.println("he()");
    }
}
public static void main(){
	Animal animal = new Dog("花花");
    animal.eat();
}

重载(overload)
1.方法名相同
2.参数列表不同(个数和类型)
3.返回值不做要求

重写(override)
1.方法名相同
2.参数列表相同(个数和类型)
3.返回值相同(若返回值构成协变类型)
协变类型:子类的返回值与父类之间返回值是继承关系

class Animal{
	public Animal eat(){
        System.out.println("chi()");
        return new Animal("小花");
    }
}
class Dog extends Animal{
	@Override
	public Dog eat() {
        System.out.println("he()");
        return new Dog("huahua");
    }
}

此时就构成了协变类型

动态绑定:
1.一定要发生向上转型
2.父类和子类有同名的重写(覆写/覆盖)方法
3.最后通过父类的引用来调用子类和父类的这个同名的覆盖方法。
此时会发生动态绑定,或者叫做运行时绑定。
注意: 在构造函数中也可以发生动态绑定(一个坑)

class Animal{
	public void eat(){
        System.out.println("chi()");
    }
    public Animal(String name){
    	eat();    //发生动态绑定
        this.name=name;
    }
}
class Dog extends Animal{
public Dog(String name){
        super(name);  
    }
	public void eat() {
        System.out.println("he()");
    }
}
public static void main(String[] args) {
	Animal animal = new Dog("花花");
}

此时在父类构造方法中发生动态绑定

重写的注意事项
1.如果当前方法是静态方法,是不可以被重写的
2.子类如果要重写父类方法,那么子类的访问修饰权限要大于等于父类的权限
3.父类中要被重写的方法一定不能是,private(私有)。
4.被final修饰的方法不能被重写(密封方法)。

4.理解多态

class Shape{
    public void draw(){

    }
}
class Cycle extends Shape{
    public void draw(){  //来重写父类方法
        System.out.println("矩形");
    }
}
class Rect extends Shape{
    public void draw(){  //重写父类方法
        System.out.println("圆形");
    }
}
public class testDome {
    public static void drawMap(Shape shape){   
        shape.draw();   //调用父类方法,子类方法进行重写发生动态绑定打印子类方法
    }
    public static void main(String[] args) {
        Cycle cycle = new Cycle();  //new子类对象
        Rect rect = new Rect();     //new子类对象
        drawMap(cycle);   //传参时发生向上转型
        drawMap(rect);    //传参时发生向上转型
    }
}

七、抽象类

包含抽象方法的类就是抽象类
抽象方法是什么:被关键字abstract修饰的方法,这个方法可以没有具体的实现。

abstract class Shape{  //密封类
    public abstract void draw();  //密封方法
}

抽象类的注意事项

  1. 抽象类可以被继承,也可以发生动态绑定,向上转型。
  2. 抽象类不可以被实例化
  3. 抽象类中的方法一定要被子类重写
  4. 抽象类存在的意义就是为了被继承,因为不能被实例化
  5. 如果一个抽象类继承了抽象类,那么可以不重写这个抽象方法。但是这个抽象类再次被一个普通类继承,就需要重写抽象方法。
  6. 抽象方法不能是private
  7. 可以包含普通的方法
  8. 抽象类不能被final修饰。

八、接口

使用关键字interface来修饰的。

1.接口的细节

  1. 接口当中的方法默认是public abstract 不能有具体实现
  2. 接口不能实例化
  3. 接口当中的方法 默认是public static final
  4. 类和接口直接的关系是implements,此时接口中的所有方法,都要被重写。
  5. 接口也可以发生向上转型 - 》 运行时绑定(动态绑定)
  6. JDK1.8开始,接口当中的方法可以有具体的实现,但这个方法一定要被default修饰。
  7. 在Java中一个类可以实现多个接口。
  8. 类和接口是implements,接口和接口之间是extends
interface IShape{   //接口
    int a = 10;    //参数默认为 public static final
    void draw();   //方法默认为 public abstract
    default void func1(){   //jdk1.8开始接口中方法有具体的实现,这个方法一定要被default修饰。
        System.out.println("123");
    }
}
class Cycle implements IShape{
    @Override
    public void draw(){
        System.out.println("○");
    }
}
public class testDome {
    public static void func(IShape iShape){
        iShape.draw();
    }
    public static void main(String[] args) {
        //IShape iShape = new IShape();   //不能进行实例化
        IShape iShape = new Cycle();   //发生向上转型
        func(iShape);
    }
}

interface A{

}
interface B{

}
interface C extends A,B{

}

2.Comparable接口

在使用自定义类型时要使用Comparable接口

class Student implements Comparable<Student>{
    public String name;
    public int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public int compareTo(Student o) {  //对自定义的数据进行排序
        //比较的规则
        /*if (this.age > o.age){
            return 1; //正值
        }else if (this.age > o.age){
            return -1;
        }else{
            return 0;
        }*/
        //return this.age - o.age;   //简化方法
        return this.name.compareTo(o.name);  //在String中实习了compareTo方法
    }
}
public class testDome {
    public static void main(String[] args) {
        Student[] student = new Student[3];
        student[0] = new Student("caocao",18);
        student[1] = new Student("liubei",26);
        student[2] = new Student("sunquan",22);
        Arrays.sort(student); //数组排序
        System.out.println(Arrays.toString(student));  //数组打印
    }
}

3.比较器(Comparator)

//类同上面Student不实现接口。
//同包不同类
public class AgeComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.age-o2.age;
    }
}
//同包不同类
public class NameComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
//主程序
    public static void main(String[] args) {
        Student[] student = new Student[3];
        student[0] = new Student("caocao",18);
        student[1] = new Student("liubei",26);
        student[2] = new Student("sunquan",22);
        NameComparator nameComparator = new NameComparator();
        Arrays.sort(student,nameComparator);
        System.out.println(Arrays.toString(student));
    }

使用比较器更方便,你想使用什么比较就自己实现一个比较器。
相比于Comparable来说,一旦类写死了一种比较方式那么就不能轻易修改了

3.Cloneable接口

Cloneable接口是一个空接口(标识接口),只是代表这个类是可以被克隆的。

class Student1 implements Cloneable{  //这个接口代表着这个类可以被克隆
    public String name;
    public int age;
    public Student1(String name,int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //Override Methods 中的clone
    @Override
    protected Object clone() throws CloneNotSupportedException {  //接口中没有clone方法,所以需要重写Object的方法
        Student1 student1 = (Student1) super.clone();   //调用父类的克隆方法给了Student1
        return student1;
    }
}
public class testDome1 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student1 student1 = new Student1("caocao",18);
        Student1 student2 = (Student1)student1.clone();
        System.out.println(student1);
        System.out.println(student2);
    }
}

Cloneable中深浅拷贝问题:
浅拷贝

class Part implements Cloneable{
    public int m = 10;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Student1 implements Cloneable{  //这个接口代表着这个类可以被克隆
    public String name;
    public int age;
    public Part a;
    public Student1(String name,int age){
        this.name = name;
        this.age = age;
        this.a = new Part();
    }
    @Override
    public String toString() {
        return "Student1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a=" + a +
                '}';
    }
    //Override Methods 中的clone
    @Override
    protected Object clone() throws CloneNotSupportedException {  //接口中没有clone方法,所以需要重写Object的方法
        Student1 student1 = (Student1) super.clone();   //调用父类的克隆方法给了Student1
        student1.a = (Part)this.a.clone();  
        return student1;
    }
}
public class testDome1 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student1 student1 = new Student1("caocao",18);
        Student1 student2 = (Student1)student1.clone();
        System.out.println(student1);
        System.out.println(student2);
    }
}

以上方法是更改浅拷贝为深拷贝

这篇关于面向对象编程(包+继承)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!