1.面向对象
面向对象的三大特性:封装性、继承性、多态性
封装
1.方法就是一种封装
2.关键字private也是一种封装
封装就是将一些细节信息隐藏起来,对于外界不可见
packagecom.dcits.day05.demo03;
public classDemo02Method {public static voidmain(String[] args) {int[] array = {5,15,25,35,111};int max =getMax(array);
System.out.println(max);
}public static int getMax(int[] array) {int max = array[0];for (int i = 0; i < array.length; i++) {if (array[i] >max) {
max=array[i];
}
}returnmax;
}
}
private关键字的作用以及使用
一旦使用了private进行修饰,那么本类中可以随意访问,但是超出了本类的范围就不能再访问了
可以通过间接访问的方式,自定义一对儿Getter/Setter方法,必须叫 setXxx 或者是 getXxx
对于Getter来说,不能有参数,返回值类型和成员变量对应
对于Setter来说,不能有返回值,参数类型和成员变量对应
//Person类
packagecom.dcits.day05.demo03;
public classPerson {
String name;private intage;public voidshow() {
System.out.println("我叫:" + name +",今年" +age);
}public void setAge(intnum) {if (num < 100 && num >=9) {
age=num;
}else{
age= 0;
System.out.println("数据不合理");
}
}public intgetAge() {returnage;
}
}
//调用
packagecom.dcits.day05.demo03;
public classDemo03Person {public static voidmain(String[] args) {
Person person= newPerson();
person.name= "赵丽颖";//person.age = 18; 当成员变量被private修饰的时候,外部无法访问,只能通过间接的方式Setter,Getter
person.setAge(-20);
person.show();
}
}
布尔类型的特殊情况
//类
packagecom.dcits.day05.demo03;
public classStudent {privateString name;private intage;private booleanmale;
public void setMale(booleanb){
male=b;
}public booleanisMale() {returnmale;
}
public voidsetName(String str){
name=str;
}publicString getName() {returnname;
}public void setAge(intnum) {
age=num;
}public intgetAge() {returnage;
}
}//调用
packagecom.dcits.day05.demo03;
public classDemo04Student {public static voidmain(String[] args) {
Student stu= newStudent();
stu.setName("alex");
stu.setAge(10);
stu.setMale(true);
System.out.println(stu.getName());
System.out.println(stu.getAge());
System.out.println(stu.isMale());
}
}
this关键字的使用
当方法的局部变量和类的成员变量重名的时候,根据就近原则,优先使用局部变量,如果需要访问 本类当中的成员变量,需要使用格式:this.成员变量
通过谁调用的方法,谁就是this
//类
packagecom.dcits.day05.demo04;
public classPerson {
String name;public voidsayHi(String name) {
System.out.println(this.name + "你好,我是" +name);
}
}//调用
packagecom.dcits.day05.demo04;
public classDemo01Person {public static voidmain(String[] args) {
Person person= newPerson();
person.name= "6666";
person.sayHi("777");
}
}
构造方法
构造方法是专门用来创建对象的方法,当我们使用关键字new来创建对象的时候,其实就是在调用构造方法
注意事项:
构造方法的名称必须和所在的类名称完全一样,就连大小写也要完全一样
构造方法不要写返回值类型,连void都不要写
构造方法不能return一个具体的返回值
如果没有编写任何构造方法,那么编译器默认会赠送一个构造方法,没有参数、方法体什么都不做
一旦编写了一个构造方法,那么编译器就不再赠送
构造 方法也是可以重载的
//类
packagecom.dcits.day05.demo04;
public classStudent {privateString name;private intage;public Student(String name,intage) {this.name =name;this.age =age;
System.out.println("有参数的构造方法!!");
}publicStudent() {
System.out.println("无参数的构造方法执行啦!!");
}public voidsetName(String name) {this.name =name;
}publicString getName() {returnname;
}public void setAge(intage) {this.age =age;
}public intgetAge() {returnage;
}
}//调用
packagecom.dcits.day05.demo04;
public classDemo02Student {public static voidmain(String[] args) {
Student stu= newStudent();
Student stu1= new Student("aaa",20);
stu1.setAge(23);
System.out.println(stu1.getAge());
System.out.println(stu1.getName());
}
}
局部变量和成员变量
定义的位置不一样
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类当中
作用范围不一样
局部变量:只有方法 才可以使用,出了方法就不能再使用了
成员变量:整个类都可以通用
默认值不一样
局部变量:没有默认值,如果想要用,必须手动赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样
内存的位置不一样
局部变量:位于栈内存
成员变量:位于堆内存
生命周期不一样
局部变量:随着方法进栈而诞生,随着方法出栈而消失
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失
标准类的组成部分
一个标准的类通常拥有下面的四个部分:
所有的成员变量都要使用private关键字来修饰
为每一个成员变量编写一对Getter、Setter方法
编写一个无参数的构造方法
编写一个全参数的构造方法
继承
继承是多态的前提,如果没有集成,就没有多态
继承解决的主要问题就是:共性抽取
定义类时的两个注意事项:
成员变量时直接定义在类当中的,在方法外面
成员方法不要写static关键字
继承的格式:
//父类
packagecom.dcits.day08.demo01;
public classEmployee {public voidmethod() {
System.out.println("父类执行!");
}
}//Teacher子类
packagecom.dcits.day08.demo01
public class Teacher extendsEmployee{
}//Assistant子类
packagecom.dcits.day08.demo01;
public class Assistant extendsEmployee {
}//调用
packagecom.dcits.day08.demo01;
public classDemo01Extends {public static voidmain(String[] args) {
Teacher teacher= newTeacher();
Assistant assistant= newAssistant();
teacher.method();
assistant.method();
}
}
在父子类的继承关系当中,如果成员变量重名,则创建子类时,访问有两种方式:
直接通过子类对象访问成员变量
等号左边是谁,就优先使用谁,没有则向上找
间接通过成员方法访问成员变量
该方法属于谁,就优先用谁,没有则向上找
//父类
packagecom.dcits.day08.demo02;
public classFu {int numFu = 10;int num = 100;public voidmethodFu() {
System.out.println(num);
}
}
//子类
packagecom.dcits.day08.demo02;
public class Zi extendsFu {int numZi = 20;int num = 200;public voidmethodZi() {
System.out.println(num);
}
}
//调用
packagecom.dcits.day08.demo02;
public classDemo01ExtendsField {public static voidmain(String[] args) {
Fu fu= newFu();
System.out.println(fu.numFu);
Zi zi= newZi();
System.out.println(zi.numFu);
System.out.println(zi.numZi);
//当父类与子类的成员变量重名的时候
System.out.println(zi.num);//System.out.println(zi.abc);//zi.methodZi();
zi.methodFu();
}
}
区分子类方法中的三种重名变量
直接使用的方法中的变量
this.变量名:调用本类中的成员变量
super.变量名:调用父类中的成员变量
//父类
packagecom.dcits.day08.demo03;
public classFu {int num = 10;
}//子类
packagecom.dcits.day08.demo03;
public class Zi extendsFu {int num = 20;public voidmethod() {int num = 30;
System.out.println(num);//30 局部变量
System.out.println(this.num); //20 本类的成员变量
System.out.println(super.num); //10 父类的成员变量
}
}//调用
packagecom.dcits.day08.demo03;
public classDemo01ExtendsField {public static voidmain(String[] args) {
Zi zi= newZi();
zi.method();
}
}
继承中成员方法的访问特点
在父子类的继承关系当中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先使用谁,如果没有则向上找
注意:无论是成员方法还是成员变量,如果没有都是向上找父类u,绝不会向下找子类
//父类
packagecom.dcits.day08.demo04;
public classFu {
public voidmethodFu() {
System.out.println("父类中的方法执行啦!");
}
public voidmethod() {
System.out.println("父类重名执行啦!");
}
}
//子类
packagecom.dcits.day08.demo04;
public class Zi extendsFu {public voidmethodZi() {
System.out.println("子类中的方法执行啦!");
}public voidmethod() {
System.out.println("子类重名执行啦!");
}
}
//调用
packagecom.dcits.day08.demo04;
public class Zi extendsFu {public voidmethodZi() {
System.out.println("子类中的方法执行啦!");
}public voidmethod() {
System.out.println("子类重名执行啦!");
}
}
继承方法中的覆盖重写
重写:方法的名称一样,参数列表也一样,覆盖、覆写
重载:方法的名称一样,参数列表不一样
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法
方法覆盖重写的注意事项:
必须保证父子类之间的方法名称相同、参数列表也相同
@Override:写在方法前面,用来检测是不是有效的正确覆盖重写,这个注释就算不写,只要满足要求,也是正确的覆盖重写
子类方法的返回值必须小于等于父类方法的返回值范围。Object类是所有类的父类
子类方法的权限必须大于等于父类方法的权限修饰符。public > protected > (default) > private 注意:(default)不是关键字default,而是什么都不写,留空
继承中方法的覆盖重写应用场景
//父类
packagecom.dcits.day08.demo06;//本来的老款手机
public classPhone {public voidcall() {
System.out.println("打电话");
}
public voidsend() {
System.out.println("发短信");
}
public voidshow() {
System.out.println("显示号码");
}
}
//子类
packagecom.dcits.day08.demo06;//上市的新款手机
public class NewPhone extendsPhone {
@Overridepublic voidshow() {//System.out.println("显示号码");
super.show();
System.out.println("显示姓名");
System.out.println("显示头像");
}
}
//调用
packagecom.dcits.day08.demo06;
public classDemo01Phone {public static voidmain(String[] args) {
Phone phone= newPhone();
phone.call();
phone.send();
phone.show();
System.out.println("===========");
NewPhone newPhone= newNewPhone();
newPhone.call();
newPhone.send();
newPhone.show();
}
}
继承中构造方法的访问特点
子类构造方法当中有一个默认隐含的 "super()" 调用,所以一定是先调用的父类构造,后执行的子类构造
子类构造可以通过super关键字来调用父类重载构造
super的父类构造调用,只能是第一个语句 ,不能一个子类构造调用多次super构造
子类必须调用父类构造方法,不写赠送super() 写了则用写的指定该的super调用,super只能有一个,还必须是第一个
super关键字的用法(访问父类的内容):
在子类的成员方法中,访问父类的成员变量
在子类的成员方法中,访问父类的成员方法
在子类的构造方法中,访问父类的构造方法
//父类
packagecom.dcits.day08.demo08;
public classFu {int num = 10;public voidmethod(){
System.out.println("父类方法");
}
}
//子类
packagecom.dcits.day08.demo08;
public class Zi extendsFu {int num = 20;publicZi(){super();
}public voidmethodZi() {
System.out.println(super.num); //父类的num
}public voidmethod(){super.method();
System.out.println("子类方法");
}
}
this关键字的三种使用方法(访问本类的内容)
在本类的成员方法中,访问本类的成员变量
在本类的成员方法中访问本类的另一个成员方法
在本类的构造方法中,访问本类的另一个构造方法
注意:
在第三种用法中要注意:this(..)调用必须是构造方法的一个语句,唯一一个
super和this两种构造调用,不能同时使用
//父类
packagecom.dcits.day08.demo09;
public classFu {int num = 30;
}//子类
packagecom.dcits.day08.demo09;
public class Zi extendsFu {int num = 20;publicZi(){this(123); //本类的无参构造,调用本类的有参构造//this(1,2)
}public Zi(intn){
}public Zi(int n,intm){
}public voidshowNum(){int num = 10;
System.out.println(num);
System.out.println(this.num); //本类中的成员变量
System.out.println(super.num); //父类中的 成员变量
}public voidmethodA() {
System.out.println("AAA");
}public voidmethodB() {
methodA();this.methodA();
System.out.println("BBB");
}
}
this、super的关键字图解
Java语言继承的三个特点:
一个类的 直接父类只能有唯一一个
Java语言可以多继承
一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类
多态
多态的定义以及基本使用
extends继承或者implements实现,是多态的前提。
小明这个对象既有学生形态,也有人类形态。一个对象拥有多种形态,这就是:对象的多态性
代码当中体现多态性,其实就是一句话:父类引用指向子类对象
格式:
父类名称 对象名 = new 子类名称()
接口名称 对象名 = new 实现类名称()
//父类
packagecom.dcits.day09.demo04;
public classFu {public voidmethod(){
System.out.println("父类方法");
}public voidmethodFu(){
System.out.println("父类特有方法");
}
}//子类
packagecom.dcits.day09.demo04;
public class Zi extendsFu {
@Overridepublic voidmethod() {
System.out.println("子类方法");
}
}//调用
packagecom.dcits.day09.demo04;
public classDemo01Multi {public static voidmain(String[] args) {//使用多态的写法//左侧父类的引用指向右侧子类的对象
Fu obj = newZi();//new 的是谁就调用谁 的方法
obj.method(); //子类方法
obj.methodFu(); //父类特有方法
}
}
多态中成员变量的使用特点
访问成员变量的两种方式:
直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有则向上找
间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则像上找
//父类
packagecom.dcits.day09.demo05;
public classFu {int num = 10;
public voidshowNum(){
System.out.println(num);
}
}//子类
packagecom.dcits.day09.demo05;
public class Zi extendsFu {int num = 20;
int age = 16;
@Overridepublic voidshowNum() {
System.out.println(num);
}
}//调用
packagecom.dcits.day09.demo05;
public classDemo01MultiField {public static voidmain(String[] args) {
Fu obj= newZi();
System.out.println(obj.num);//父类中的10
System.out.println("=====================");
obj.showNum();//子类没有覆盖重写,就是父类中的num,一旦子类重写后就是子类中的num
}
}
多态中成员方法的使用特点
在多态的代码当中,成员方法的优先访问规则是:看new的是谁,就优先用谁,没有则向上找
注意:编译看左边,运行看右边
对比一下:
成员变量:编译看左边,运行还看左边
成员方法:编译看左边,运行看右边
//父类
packagecom.dcits.day09.demo05;
public classFu {int num = 10;
public voidshowNum(){
System.out.println(num);
}
public voidmethod(){
System.out.println("父类方法");
}public voidmethodFu(){
System.out.println("父类特有方法");
}
}//子类
packagecom.dcits.day09.demo05;
public class Zi extendsFu {int num = 20;
int age = 16;
@Overridepublic voidshowNum() {
System.out.println(num);
}
@Overridepublic voidmethod() {
System.out.println("子类方法");
}public voidmethodZi(){
System.out.println("子类特有方法");
}
}
//调用
packagecom.dcits.day09.demo05;
public classDemo01MultiField {public static voidmain(String[] args) {
Fu obj= newZi();
obj.method();//父子都有,优先使用子类
obj.methodFu(); //子类没有,父类有,向上找到父类//编译看左,左边是Fu,没有methodZi方法,所以编译报错//obj.methodZi();//错误写法
//System.out.println(obj.num);//父类中的10//System.out.println("=====================");//obj.showNum();//子类没有覆盖重写,就是父类中的num,一旦子类重写后就是子类中的num
}
}
使用多态的好处
对象的向上转型
对象的向上转型,其实就是多态写法
格式: 父类名称 对象名 = new 子类名称()
含义:右侧创建一个子类对象,把它当作父类来看待使用
注意事项:
向上转型一定是安全的,从小范围转到了大范围
但是有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本的特有内容
类似于:double num = 100 正确 int----double 自动类型转换
//父类
packagecom.dcits.day09.demo06;
public abstract classAnimal {public abstract voideat();
}//子类
packagecom.dcits.day09.demo06;
public class Cat extendsAnimal {
@Overridepublic voideat() {
System.out.println("猫吃鱼。。。");
}
}
//调用
packagecom.dcits.day09.demo06;
public classDemo01Main {public static voidmain(String[] args) {
Animal animal= newCat();
animal.eat();
}
}
对象的向下转型
对象的向下转型,其实是一个还原动作
格式:子类名称 对象名 = (子类名称) 父类对象
含义:将父类对象,还原成为原本的子类对象
注意事项:
必须保证对象本来创建的时候,就是猫,才能向下转型成为猫
如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错
类似于:int num = (int) 10.0 正确 int num = (int) 10.5 错误,发生精度损失
//父类
packagecom.dcits.day09.demo06;
public abstract classAnimal {public abstract voideat();
}//猫子类
packagecom.dcits.day09.demo06;
public class Cat extendsAnimal {
@Overridepublic voideat() {
System.out.println("猫吃鱼。。。");
}
public voidcatchMouse() {
System.out.println("猫抓老鼠!!");
}
}
//狗子类
packagecom.dcits.day09.demo06;
public class Dog extendsAnimal {
@Overridepublic voideat() {
System.out.println("狗吃shit");
}
public voidwatchMouse() {
System.out.println("狗看家!!");
}
}
//调用
packagecom.dcits.day09.demo06;
public classDemo01Main {public static voidmain(String[] args) {
Animal animal= new Cat(); //对象的向上转型
animal.eat();
//向下转型
Cat cat =(Cat) animal;
cat.catchMouse();//猫抓老鼠!!
//下面是错误的向下转型//本来new的时候是一只猫,现在非要转成狗//java.lang.ClassCastException
Dog dog = (Dog) animal; //错误写法
}
}
用instanceof 关键字进行类型判断
packagecom.dcits.day09.demo06;
public classDemo01Instanceof {public static voidmain(String[] args) {
Animal animal= new Cat(); //本来是一只猫
animal.eat();
//如果需要调用子类特有的方法,需要向下转型
if (animal instanceofDog){
Dog dog=(Dog) animal;
dog.watchMouse();
}if (animal instanceofCat){
Cat cat=(Cat) animal;
cat.catchMouse();
}
giveMeAPet(new Dog()); //在你调用这个方法的时候,方法本身不知道传递过来的是哪个类,所以需要进行判断
}
public static voidgiveMeAPet(Animal animal){if (animal instanceofDog){
Dog dog=(Dog) animal;
dog.watchMouse();
}if (animal instanceofCat){
Cat cat=(Cat) animal;
cat.catchMouse();
}
}
}
接口多态的综合案例
//USB接口类:两个抽象方法:打开USB、关闭USB
packagecom.dcits.day09.demo07;
public interfaceUSB {
public abstract voidopen();
public abstract voidclose();
}
//电脑类:开机、关机、连接USB接口并对USB设备进行对应操作
packagecom.dcits.day09.demo07;
public classComputer {public voidpowerOn(){
System.out.println("笔记本电脑开机");
}
public voidpowerOff(){
System.out.println("笔记本电脑关机");
}
//使用USB设备的方法,使用接口作为方法的参数
public voiduseDevice(USB usb) {
usb.open();//判断当前类是属于哪个类之后,在获取类中的特有方法
if (usb instanceofMouse){
Mouse mouse=(Mouse) usb;
mouse.click();
}else if (usb instanceofKeyBoard){
KeyBoard keyboard=(KeyBoard) usb;
keyboard.type();
}
usb.close();
}
}
//鼠标类:重写接口类中的打开、关闭功能,并实现自己的独有功能
packagecom.dcits.day09.demo07;
public class Mouse implementsUSB {
@Overridepublic voidopen() {
System.out.println("打开鼠标");
}
@Overridepublic voidclose() {
System.out.println("关闭鼠标");
}
public voidclick(){
System.out.println("点击鼠标!");
}
}
//键盘类:重写接口类中的打开、关闭功能,并实现自己的独有功能
packagecom.dcits.day09.demo07;
public class KeyBoard implementsUSB {
@Overridepublic voidopen() {
System.out.println("打开键盘");
}
@Overridepublic voidclose() {
System.out.println("关闭键盘");
}
public voidtype(){
System.out.println("敲键盘!");
}
}