包
包的本质
- 包的本质就是创建不同的文件夹来保存同一个程序所需要的类文件
包的命名
- 命名规则:只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字或保留字
- 命名规范:一般是小写字母+小圆点,规定通常是域名的倒写,如www.baidu.com====> com.baidu.www
包的引用
-
不同包中含有同名类时在创建对象引用时需要在对象引用前加上完整包名
-
import的使用
1.引用util包下Scanner这一个具体类 import java.util.Scanner; 2.引用util包下的所有类,但不同于c语言中将头文件中的内容全部导入 JVM会在你调用util包中某个具体的类时自动导入 import java.util.*;
包的细节
- package的作用是声明当前类所在的包,需要放在class的最上面,一个类中最多只有一句package
- import指令位置放在package下面,在类定义前面,可以有多句且没有顺序的要求
常用包介绍
- java.lang(lang包是基本包,默认引入,不需要再引入)
- java.util(util包,系统提供的工具包,工具类)
- Java.net(网络包,网络开发)
- java.awt(是做Java的界面开发,GUI)
继承
基本介绍
-
基本语法
class 子类 extends 父类{}// B类继承了A类 class B extends A{} class A{}
1 子类会自动拥有父类定义的属性和方法
2 父类又叫超类、基类
3 子类又叫派生类 -
便利性
- 提高了代码的复用性:当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
- 代码的扩展性和维护性提高了:维护时只需要维护具体子类即可,扩展则可以在父类中添加子类共用代码。
使用细节
-
子类继承了父类所有非私有属性,私有属性不能在子类直接访问, 要通过父类提供公共(public)的get方法去访问(原理是让父类中的public方法去访问private属性(方法),然后返回该private属性(在该方法中调用一次private方法),然后用子类去访问父类中该public方法)
class Person{ //私有属性 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;} } class Student extends Person{ public static void main(String[] args) { Student student = new Student(); //访问父类中的私有属性 student.setAge(11); student.setName("小明"); System.out.println(student.getAge()); System.out.println(student.getName()); } }
-
子类必须调用父类的构造器,完成父类的初始化(自动),子类中会默认调用super()语句,写不写都会发挥该语句的功能:调用父类的构造器
class Student extends Person{ public Student(){ // super(); 默认调用无参构造器 } }
-
当创建子类对象时,不管是用哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化操作,否则编译不通过
class Person{ public Person(int age){ System.out.println("父类有参构造器"); } } class Student extends Person{ public Student(){ super(11); } }
-
如果希望指定去调用父类的某个构造器,在子类的构造器中要显示的调用一下(super(参数列表))
-
super在使用时,需要放在构造器第一行
-
super()和this()都只能放在构造器第一行,因此这两个方法不能共存一个构造器
-
java所有类都是object类的子类
-
父类构造器的调用不限于直接父类!将一直往上追溯直到Object类
-
子类最多只能继承一个父类(指直接继承,只能有一个father),即Java是单继承机制
-
不能滥用继承,子类和父类之间必须满足is-a的逻辑关系
-
继承的本质分析
- 首先先加载类的信息(Object->grandpa->father->son)
- 在堆中开辟空间,然后按照类从上到下依次分布内存
- 然后在栈中开辟对象引用指向堆中的对象
- 访问顺序:首先看子类是否有该属性;如果子类有这个属性,并且可以访问,则返回信息;如果子类没有该属性,找其直接父类,然后依次往上寻找(当其较低级的父类中的属性访问有权限限制时会直接报错,即使其较高级的父类中有同名属性也不会访问)
多态
基本介绍
- 方法或对象具有多种形态(方法重载和方法重写就体现多态)
- 对象多态:
- 一个对象的编译类型和运行类型不一致,父类的引用可以指向子类对象(Animal animal = new Cat();)animal的编译类型是Animal,运行类型是Cat
- 编译类型在定义对象时就确定了,不能改变
- 运行类型是可以变化(animal = new Dog())
- 编译类型看’=‘左边,运行类型看’='右边
使用细节
-
多态的前提是两个类存在继承关系
-
多态的向上转型
-
本质:父类的引用指向子类的对象
-
语法:
父类类型 引用名 = new 子类类型; 父类类型 引用名 = (父类类型) 子类引用名;
-
特点
可以调用父类的所有成员(遵循访问权限)
不能调用子类的特有成员(编译阶段能调用哪些类型由编译类型确定)
-
-
多态的向下转型
-
语法:
子类类型 引用名 = (子类类型) 父类引用名 Animal animal = new Cat(); Cat cat = (Cat)animal; 与 Cat cat1 = new Cat()不一样的是, cat和animal指向堆中的同一个对象, 而cat1指向堆中新开辟的一个对象。
-
只能强转父亲类型的引用,不能强转父亲的对象
-
要求父亲的引用必须指向当前目标类型对象
-
可以调用子类类型中所有成员
-
-
动态绑定机制:通过子类覆盖父类的方法来实现多态
1.当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
2.当调用对象属性时,没有动态绑定机制,哪里声明哪里使用
-
静态绑定机制:通过方法重载来实现,即在一个类中定义多个同名的不同方法来实现多态
-
多态的应用
-
多态数组:数组的定义类型为父类类型,里面保存的实际元素类型可以是父类类型,也可以是子类类型
public class Test { public static void main(String[] args) { //多态数组存放不同的类型 Person[] person = new Person[2]; person[0] = new Student(); person[1] = new Teacher(); } } class Person{ } class Student extends Person{} class Teacher extends Person{}
-
多态参数:方法定义的形参类型为父类,实参允许为子类
public class Test { public static void main(String[] args) { Student student = new Student(); Teacher teacher = new Teacher(); //形参为父类,实参为不同子类 f1(student); f1(teacher); } public static void f1(Person person) { } } class Person { } class Student extends Person { } class Teacher extends Person { }
-
抽象类
基本介绍
- 由来:当父类的一些方法不能确定时,可以用abstract关键字修饰该方法,这个方法就是抽象方法,用abstract来修饰该类就是抽象类
- 抽象类格式:访问修饰符 abstract 类名{}
- 抽象方法格式:访问修饰符 abstract 返回类型 方法名(参数列表) 没有方法体
- 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类
使用细节
-
抽象类不能实例化,但是可以通过多态向上转型!
-
抽象类可以有抽象方法,也可以没有抽象方法
abstract class Animal{ 抽象方法 abstract void f1(); 具体方法 int f2(){ return 0; } }
-
一旦类包含了abstract方法,该类必须声明为抽象类
-
abstract只能修饰类和方法,不能修饰属性和其他的
-
抽象类还是类,可以有任意成员
-
抽象方法不能有主体(即{功能实现})
-
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类,但最后一定会有一个具体的类实现所有抽象父类的方法
abstract class Animal{ abstract void f1(); } class Cat extends Animal{ 子类必须将继承的抽象父类中的所有抽象方法进行重写,否则编译会出错 @Override public void f1(){ System.out.println("haha"); } }
-
抽象方法不能用private、final和static来修饰,因为这些关键字都是和重写相违背的。private无法被子类访问,更不能重写,final不能被重写,static本身就是一种工具型,无须创建对象,与重写无关
接口
基本介绍
- 定义:接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
- 语法
interface 接口名{ 属性 方法}
class 类名 implements 接口名{ 自己属性 自己方法 必须实现的接口的抽象方法}
//在接口中,抽象方法可以省略abstract关键字
使用细节
-
接口与抽象类一样不能被实例化,但可以通过多态向上转型
-
接口中所有的方法都是public方法(不用写public),抽象方法不用abstract关键字,在jdk8.0之后接口中可以出现默认方法(default)和静态方法
interface A{ 静态方法 public static void f1(){ } 默认方法 public default void f2(){ } }
-
一个类实现接口需要把接口中的所有抽象方法全部实现
-
抽象类实现接口,可以不实现接口的方法
-
一个类可以同时实现多个接口
interface IB{} interface IC{} class A implements IB,IC
-
接口中的属性只能是final的,而且是public,static,final修饰符,因此必须被初始化(常量)
interface UD{ int a = 1; //实际上是 public static final int a = 1; }
-
接口与接口之间用extends关键字,用以拓展某个接口的功能(可以拓展多个接口);类与类之间用extends关键字,用以继承父类中公共代码,提高代码复用性(单一继承性);类与接口之间用implements关键字,用以实现接口中的功能(可以实现多个接口)
-
一个接口不能继承其他的类,但是可以拓展多个别的接口(接口和接口之用extends关键字)
-
接口的修饰符只能是public和默认,和类的修饰符一样
-
接口的多态特性
-
多态参数:和继承中的父类当参数一样,接口也可以当参数,然后接收各种实现该类的对象
-
多态数组;可以存放不同的实现该类的对象(继承父类的子类可以存放父类对象,但是接口不能被实例化,所以不能存放“接口对象”)
-
接口存在多态传递现象
interface IH{} interface IG extends IH{} class Teacher implements IG{ } public class Inter{ public static void main(String[] args){ IG ig = new Teacher(); IH ih = new Teacher(); //这个语句正确 } }
-
常用接口
-
Comparable:缺点是对类的侵入性非常强,会直接改动源码
class Student implements Comparable<Student>{ public int age; public String name; public double grade; public Student(int age, String name, double grade) { this.age = age; this.name = name; this.grade = grade; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + ", grade=" + grade + '}'; } @Override public int compareTo(Student o) { return o.age - this.age; } }
-
Comparator(比较器):灵活,对类的侵入性小
class A implements Comparator<Student>{//传入参数 @Override public int compare(Student o1, Student o2) { return o1.age - o2.age; } } public class Test { public static void main(String[] args) { int[] arr = {1,23,12,3,4}; Student[] stu = new Student[3]; stu[0] = new Student(11,"jack",78); stu[1] = new Student(15,"smith",188); stu[2] = new Student(6,"atom",98); Arrays.sort(stu, new Comparator<Student>() { //直接在这传入Comparator接口参数 @Override public int compare(Student o1, Student o2) { return o1.age - o2.age; } }); System.out.println(Arrays.toString(stu)); } }
-
Cloneable:深拷贝
总结
本篇文章主要介绍了java中的包、三大特性中的继承、多态以及抽象类和接口。希望大家能够有所收获!