目录
继承
- 只能存在一个父类,可以存在多个子类。
- 父类的私有成员(访问权限为private的成员)不能被子类继承。
- 子类继承父类的成员,同时可以定义其他的成员。
- 允许存在多重继承,即子继承父,父继承爷。
继承实现
class 子类名称 extends 父类名称 {
}
实例
class Person {
int age;
public char gender;
protected String name;
private String dream;
void msgPrintf(){
System.out.println("age is " + age);
System.out.println("gender is " + gender);
System.out.println("name is " + name);
}
//私有方法
private void myPrintf(){
System.out.println("hello");
}
} //父类(只能存在一个父类,可以存在多个子类):人
//子类:老师
class Teacher extends Person {
void teacherDream(){
System.out.println("become teacher");
}
}
//子类:学生
class Student extends Person {
void studentDream(){
System.out.println("become programmer");
}
}
public class Text {
public static void main(String[] args) {
Teacher t1 = new Teacher();
t1.age = 25;
t1.gender = '女';
t1.name = "jiangxiaoya";
//t1.dream = "become teacher"; 由于父类Person中的dream是私有成员,因此无法被子类Teacher继承
//t1.myPrintf(); 由于父类Person中的myPrintf()是私有方法,因此无法被子类Teacher继承
t1.msgPrintf();
t1.teacherDream();
System.out.println();
Student s1 = new Student();
s1.age = 19;
s1.gender = '男';
s1.name = "haozige";
//s1.dream = "become programmer"; 由于父类Person中的dream是私有成员,因此无法被子类Student继承
//s1.myPrintf(); 由于父类Person中的myPrintf()是私有方法,因此无法被子类Teacher继承
s1.msgPrintf();
s1.studentDream();
}
}
方法重写
- 当子类与父类有相同的方法时(即方法名相同、返回值类型相同、参数列表相同),此时使用创建的子类对象使用该方法时,使用的是子类的方法,即方法重写。
- 当子类和父类的方法名相同,参数列表不同时,此时使用创建的子类对象使用该方法时,使用的是子类的方法,但属于方法重载。
- 方法重写发生在继承类中,被重写的方法不能有更严格的权限,而方法重载发生在一个类中,对权限没有要求。
- 当子类存在与父类相同的数据成员时,优先使用子类的数据成员。
实例
class Person {
int age = 99;
public char gender;
protected String name;
private String dream;
void msgPrintf(){
System.out.println("age is " + age);
System.out.println("gender is " + gender);
System.out.println("name is " + name);
}
} //父类:人
//子类:学生
class Student extends Person {
//方法重写,与父类的方法名相同,参数列表相同
void msgPrintf(){
System.out.println("my dream is become programmer");
}
}
class Teacher extends Person {
int age = 40; //当子类存在与父类相同的数据成员时,优先使用子类的数据成员
//方法重载,与父类的方法名相同,参数列表不同
void msgPrintf(String name){
System.out.println(age);
System.out.println(name);
}
}
public class Text {
public static void main(String[] args) {
Student s1 = new Student();
s1.msgPrintf();
System.out.println();
Teacher t1 = new Teacher();
t1.msgPrintf("jiangxiaoya");
}
}
继承的构造方法的执行顺序
- 当执行子类的构造方法时,父类以及父类的上一级结构的构造方法都会被执行,执行顺序是从最年老的到最年轻的。
- 当子类有多个构造方法时,无论子类创建的对象使用哪个构造方法,父类以及父类的上一级结构都只会执行默认的构造方法(无参数的构造方法)。
典例
class Person {
//构造方法
Person() {
System.out.println("我是人");
}
Person(String name) {
System.out.println(name);
}
} //父类:人
//子类:学生
class Student extends Person {
//构造方法
Student() {
System.out.println("我是学生");
}
Student(String name) {
System.out.println(name);
}
}
class Haozige extends Student {
//构造方法
Haozige() {
System.out.println("我是浩子哥");
}
Haozige(String name) {
System.out.println(name);
}
}
public class Text {
public static void main(String[] args) {
new Haozige("haozige"); //执行匿名对象Haozige的构造方法
}
}
super关键字
用途:
- 在子类的构造方法中调用父类的构造方法。(子类创建对象时,部分数据成员使用父类的数据成员的值)
- 当子类调用构造方法时,父类也会调用默认的构造方法,因此super关键字应用场景是调用父类有参数的构造方法
- 在子类中调用父类的数据成员或者方法。(调用父类数据成员,当给子类的数据成员赋值之后,即使使用super关键字调用父类数据成员时,使用的也是子类成员的值)
实例
class Student {
int age;
char gender;
String name = "学生名字未知";
String greet;
Student() {
this.greet = "I am a Student";
}
void studentPrintf(){
System.out.println("hello teacher");
}
}
class Haozige extends Student {
public Haozige(int age,char gender,String name) {
super(); //调用父类的构造方法
this.age = age;
this.gender = gender;
this.name = name;
}
void msgPrintf(){
System.out.println(super.name); //调用父类数据成员,当给子类的数据成员赋值之后,即使使用super关键字调用父类数据成员时,使用的也是子类成员的值
super.studentPrintf(); //调用父类方法
System.out.println(age);
System.out.println(gender);
System.out.println(greet);
}
}
class Jiangxiaoya extends Student {
void msgPrintf(){
System.out.println(super.name); //调用父类数据成员
}
}
public class Text {
public static void main(String[] args) {
new Haozige(19,'男',"haozige").msgPrintf();
System.out.println();
new Jiangxiaoya().msgPrintf();
}
}
final关键字
- 当使用final关键字修饰数据成员时,声明该数据成员是一个常量(定义常量时应该进行初始化),常量的值不能改变。
- 当使用final关键字修饰父类的方法时,子类继承时不能进行该方法的方法重写,但可以进行该方法的方法重载。
- 当final关键字修饰类时,声明该类不能由其他类继承,即不能拥有孩子。
实例
class Person {
int age;
char gender;
String name = "jiangxiaoya";
final String greet = "I am a Person";
final void msgPrintf(){
System.out.println("hello");
}
void changeMsg(){
name = "haozige";
//greet = "I am Student"; 数据成员常量不能被改变
}
}
final class Student extends Person {
//void msgPrintf(){} 由于父类的msgPrintf方法添加了final关键字,因此子类继承时不能进行方法重写,但能进行方法重载。
void msgPrintf(String name){
System.out.println(name);
}
}
//class Jiangxiaoya extends Student{} 由于类Student添加了final关键字,因此不能生产孩子
public class Text {
public static void main(String[] args) {
new Student().msgPrintf("zhutoucai");
}
}
static关键字
- static修饰数据成员时称为静态成员,static修饰方法时称为静态方法,类的静态成员和静态方法不需要创建对象就能使用。
- 静态方法只可以使用静态成员和调用静态方法。
- 如果父类有静态方法,那么子类不能进行该方法的方法重写,但可以进行方法重载,或者使用相同的方法名也定义为静态方法。
实例
class Student {
static int age;
char gender;
String name;
static void initAge(){
age = 99; //如果age不是静态成员,则会报错,静态方法只可以使用静态成员和调用静态方法
}
void initName(){
name = "student";
}
}
class Haozige extends Student {
//不能进行方法重写,但可以对父类的静态方法进行方法重载
void initAge(int age){
System.out.println(age);
}
}
class Jiangxiaoya extends Student {
//使用与父类相同的方法名也定义为静态方法,不知道是不是属于方法重写
static void initAge(){
age = 19;
System.out.println(age);
}
}
public class Text {
public static void main(String[] args) {
new Haozige().initAge(21);
System.out.println();
Jiangxiaoya.initAge(); //调用静态方法时,可以不用创建对象
}
}
抽象类与抽象方法
- 使用abstract关键字定义抽象类。
- 抽象类是一个模板父类,让继承的子类实现模板父类的抽象方法,因此抽象类不能使用new关键字创建对象,只能被其他类继承。
- 抽象类里面允许存在普通方法和数据成员和构造方法,但必须存在一个或一个以上的抽象方法,即主体内容都是抽象方法。
- 抽象类被子类继承后,子类必须对抽象方法进行方法重写(即抽象方法的具体化)。
- 继承抽象类的子类可以在构造方法中使用super关键字调用抽象类的构造方法,或者使用super关键字调用普通方法。
定义抽象类
abstract class 类名称 {
数据成员;
普通方法{
}
修饰符 abstract 抽象方法;
}
实例
//使用abstract关键字定义抽象类
abstract class Student {
//数据成员
int age;
char gender;
String name;
String greet;
//构造方法1
Student() {
this.greet = "父类构造方法1";
}
//构造方法2
Student(int age) {
this.greet = "父类构造方法2";
}
//普通方法
void myPrintf(){
System.out.println("hello");
}
//抽象方法
abstract void msgPrintf();
}
//继承抽象类
class Haozige extends Student {
//子类的构造方法
Haozige(int age,char gender,String name){
super(99); //使用super关键字调用父类的构造方法2,注释掉该行时,会调用父类的构造方法1
this.age = age;
this.gender = gender;
this.name = name;
}
//实现抽象方法
public void msgPrintf() {
System.out.println(name);
System.out.println(age);
System.out.println(gender);
System.out.println(greet);
super.myPrintf(); //调用父类的普通方法
}
}
public class Text {
public static void main(String[] args) {
Haozige h1 = new Haozige(20, '男', "haozige");
h1.msgPrintf();
}
}
接口
接口和抽象类的区别
- 接口类似于抽象类,只提供方法的定义,让使用接口的类实现接口定义的方法
- 一个类只能继承一个父类,而一个类能实现多个接口 ,处于不同层次的类可以实现同一个接口
- 抽象类有数据成员、常量、普通方法和抽象方法,而接口只有常量和抽象方法
- 接口内的方法在编译时,自动变成public和abstract类型,即变成公有抽象方法,而接口内的数据成员在编译时,自动变成public和final类型,即变成公有常量。
接口的定义和使用
- 使用interface关键字定义接口,类使用implements实现接口
- 接口的数据成员必须赋值,编译时会变成常量
- 不能将接口方法声明为私有接口方法
定义接口
interface 接口名称 {
修饰符 数据成员
修饰符 普通方法;}
实例
//定义接口1
interface Haozige {
int age = 20; //接口内定义的数据成员必须进行初始化,因为他们编译后会变成公有常量
String name = "haozige";
//接口方法
void haozigePrintf(); //接口方法在编译时会变成公有抽象方法
}
//定义接口2
interface Jiangxiaoya {
int age = 19;
String name = "jiangxiaoya";
//接口方法
void jiangxiaoyaPrintf();
}
//实现接口的类
class Teacher implements Haozige{
//实现接口方法
public void haozigePrintf(){
System.out.println(age); //使用接口的常量
System.out.println(name);
}
}
//一个类可以同时实现多个接口
class Student implements Haozige,Jiangxiaoya {
//实现Haozige接口的接口方法
public void haozigePrintf(){
System.out.println(Haozige.age); //使用接口的常量,如果实现了多个接口,接口的常量名重合时,使用接口名来区分常量
System.out.println(Haozige.name);
}
//实现Jiangxiaoya接口的接口方法
public void jiangxiaoyaPrintf(){
System.out.println(Jiangxiaoya.age);
System.out.println(Jiangxiaoya.name);
}
}
public class Text {
public static void main(String[] args) {
new Teacher().haozigePrintf();
System.out.println();
new Student().haozigePrintf();
System.out.println();
new Student().jiangxiaoyaPrintf();
}
}
接口继承
- 接口也可以像类一样继承,即子接口使用extends关键字继承父接口
- 实现子接口的类不仅要实现自子接口的接口方法,还要实现父接口或更上层接口的接口方法
实例
//定义接口Person
interface Person {
void personPrintf();
}
//定义子接口继承父接口Person
interface Student extends Person {
void studentPrintf();
}
//定义一个类实现子接口
class Haozige implements Student {
//实现子接口接口方法
public void studentPrintf(){
System.out.println("我是子接口");
}
//如果父接口或者更上层接口的接口方法没有实现就会报错
public void personPrintf() {
System.out.println("我是父接口");
}
}
public class Text {
public static void main(String[] args) {
new Haozige().studentPrintf();
new Haozige().personPrintf();
}
}
多态
多态能让不同对象执行相同的方法却能实现不同的结果
抽象类实现多态
抽象类对象能够引用子类的对象,当引用成功后,能使用子类对象的数据成员和方法。
实例
import java.util.Scanner;
//定义一个抽象类
abstract class Dayindian {
String dName = "谢谢惠顾,你购买的打印机是";
abstract void myPrintf();//
}
class HeibaiDayinji extends Dayindian {
String hName = "黑色打印机";
void myPrintf() {
System.out.println("黑白打印机");
System.out.println(hName);
}
}
class CaisheDayinji extends Dayindian {
String cName = "彩色打印机";
void myPrintf() {
System.out.println("彩色打印机");
System.out.println(cName);
}
}
public class Text {
public static void main(String[] args) {
//让一个抽象类对象,根据不同的程序逻辑引用不同的子对象,来使用子对象的方法
Dayindian d;//声明抽象类对象
HeibaiDayinji h = new HeibaiDayinji();//创建黑白打印机对象
CaisheDayinji c = new CaisheDayinji();//创建彩色打印机对象
Scanner sc = new Scanner(System.in); //使用输入类
int tmp;
while(true){
System.out.println("欢迎光临");
System.out.println("请选择打印机:1.黑白打印机 2.彩色打印机 3.不买了");
tmp = sc.nextInt();
if(tmp == 1){
d = h; //让抽象类对象引用黑白打印机对象
}else if(tmp == 2){
d = c; //让抽象类对象引用彩色打印机对象
}else{
break;
}
System.out.println(d.dName); //使用抽象类的数据成员
d.myPrintf(); //当对象类引用子类对象成功后,使用抽象类方法时,将会调用子类方法
}
}
}
实例分析
没引用对象前的内存分配
Dayindian d; //声明抽象类对象
HeibaiDayinji h = new HeibaiDayinji(); //创建黑白打印机对象
CaisheDayinji c = new CaisheDayinji(); //创建彩色打印机对象
d = h; //让抽象类对象引用黑白打印机对象
d = c; //让抽象类对象引用彩色打印机对象
接口实现多态
当某个子类已经继承一个父亲时,该子类无法通过继承一个抽象类来完成多态(即该子类同时只能拥有一个父亲),因此只能选择用接口完成多态。
实例
接口实现多态跟抽象类实现多态大同小异
import java.util.Scanner;
//定义一个接口
interface Dayindian {
String dName = "谢谢惠顾,你购买的打印机是";
void myPrintf();
}
class HeibaiDayinji implements Dayindian {
String hName = "黑色打印机";
public void myPrintf() {
System.out.println("黑白打印机");
System.out.println(hName);
}
}
class CaisheDayinji implements Dayindian {
String cName = "彩色打印机";
public void myPrintf() {
System.out.println("彩色打印机");
System.out.println(cName);
}
}
public class Text {
public static void main(String[] args) {
Dayindian d;//声明接口对象
HeibaiDayinji h; //声明黑白打印机对象
CaisheDayinji c; //声明彩色打印机对象
Scanner sc = new Scanner(System.in); //使用输入类
int tmp;
while(true){
System.out.println("欢迎光临");
System.out.println("请选择打印机:1.黑白打印机 2.彩色打印机 3.不买了");
tmp = sc.nextInt();
if(tmp == 1){
//h = new HeibaiDayinji();
//d = h;
d = new HeibaiDayinji(); //让接口对象引用黑白打印机对象
}else if(tmp == 2){
//c = new CaisheDayinji();
//d = c;
d = new CaisheDayinji(); //让接口对象引用彩色打印机对象
}else{
break;
}
System.out.println(Dayindian.dName); //使用接口的数据成员
d.myPrintf();
}
}
}
包
包的功能及介绍
包的功能
- 解决命名冲突的问题,同一个包中的类名不能相同
- 将同一个类型的类集中在一个包中,让项目整体架构更清晰
包的介绍
- 一个包中能存在多个.java文件。
- 一个.java文件中只能存在一个公有类,该公有类名字与.java文件的名字必须一样,可以存在多个默认类。
包的定义
包的创建
在src目录下->New->Package
在包中创建类
在包目录下->New->Class
类和类成员权限的设定
类的权限
类的权限只有public和默认,即类按权限分为公有类和默认类
- 公有类:能在同一个包中或者不同的包中使用该公有类。
- 默认类:只能在同一个包中使用该默认类。
类成员的权限
- private(私有成员):只有同一个类可以使用
- 默认(默认成员):同一个包中的类可以使用
- protected(保护成员):同一个包中的类都可以使用,以及不同包中的非子类可以使用
- public(公有成员):任何包中的类都可以使用
包的引用
引用包中某个公有类
import 包名称.类名
引用包中所有的公有类
import 包名称.*