面向对象(Object Oriented)
Java支持面向对象三大特性:封装、继承、多态。(抽象)
1、封装(Encapsulation)
封装:隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通常有两种访问方式:set 设置,get 获取。
程序设计要追求“高内聚,低耦合”
• 高内聚 :就是类的内部数据操作细节自己完成,不允许外部干涉;
• 低耦合 :仅暴露少量的方法给外部使用
封装的具体优点:
1. 提高代码的安全性。
2. 提高代码的复用性。
3. “高内聚”:封装细节,便于修改内部代码,提高可维护性。
4. “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
Java是使用“访问控制符”来控制哪些细节需要封装,Java中4种“访问控制符”分别为 private、default、protected、public,它们说明了面向对象的封装性,使用修饰符尽可能的让访问权限降到最低,从而提高安全性。
1. private 表示私有,只有自己类能访问
2. default表示没有修饰符修饰,只有同一个包的类能访问
3. protected表示可以被同一个包的类以及其他包中的子类访问
4. public表示可以被该项目的所有包中的所有类访问
1 package com.test; 2 3 /** 4 * 封装的应用 5 * 6 * @author Administrator 7 * 8 */ 9 public class EncapsulationTest { 10 public static void main(String[] args) { 11 Student student = new Student("小明", "男", 18, 60); 12 student.showInformation(); 13 14 Student student2 = new Student(); 15 student.setName("小红"); 16 student.setGender("男"); 17 student.setAge(18); 18 student.setScore(60); 19 student.showInformation(); 20 21 } 22 23 } 24 25 // 创建学生类对象 26 class Student { 27 // 属性设置私有性,对外提供getter.setter方法 28 private String name; 29 private String gender; 30 private int age; 31 private int score; 32 33 // 无参构造函数 34 public Student() { 35 } 36 37 // 有参构造函数 38 public Student(String name, String gender, int age, int score) { 39 super(); 40 this.name = name; 41 this.gender = gender; 42 this.age = age; 43 this.score = score; 44 } 45 46 // getter.setter方法 47 public String getName() { 48 return name; 49 } 50 51 public void setName(String name) { 52 this.name = name; 53 } 54 55 public String getGender() { 56 return gender; 57 } 58 59 public void setGender(String gender) { 60 this.gender = gender; 61 } 62 63 public int getAge() { 64 return age; 65 } 66 67 public void setAge(int age) { 68 this.age = age; 69 } 70 71 public int getScore() { 72 return score; 73 } 74 75 public void setScore(int score) { 76 this.score = score; 77 } 78 79 public void showInformation() { 80 System.out.println("Student [name=" + name + ", gender=" + gender + ", age=" + age + ", score=" + score + "]"); 81 } 82 83 }
关于类成员的权限的使用的基本原则:
1:类中的成员变量要求全部私有。如果其他的类有访问私有成员变量的需求,那么统一的提供访问器和修改器来提供访问的功能。getter 和 setter
2:所有的类中的成员的访问权限,要尽量的小。越小越好。
3:如果某个类不想被实例化,那么构造方法私有化。
类的访问权限:在class 关键字 前面 添加的 类的被访问的权限。
类的访问权限 就 2个
1:public:工程级别的访问权限,所有的本工程的类,都可以访问使用public 修饰的类。
2:默认的:本包其他的类。
2、构造器
用于创建对象并初始化对象属性的方法,叫“构造方法”,也叫“构造器”;构造器在类中定义。
1)构造器的名称必须与类名同名,包括大小写。
2)构造器没有返回值,但也不能写 void,也不能写 return。
3)构造器的参数:一般是初始化对象的前提条件。
4)用 new 调用!且对象一建立,构造器就运行且仅运行一次。一般方法可被调用多次。
5)如果类没有声明(定义)任何的构造器,Java 编译器会自动插入默认构造器!
6)默认构造是无参数,方法体是空的构造器,且默认构造器的访问权限随着所属类的访问权限变化而变化。如,若类被 public 修饰,则默认构造器也带 public 修饰符。
7)默认构造器是看不到的,一旦自定义构造器则默认构造器就没有了,自己写的叫自定义构造器,即便自己写的是空参数的构造器,也是自定义构造器,而不是默认构造器。
8)如果类声明了构造器,Java 编译器将不再提供默认构造器。若没手动写出无参构造器,但却调用了无参构造器,将会报错!
9)构造器是可以重载的,重载的目的是为了使用方便,重载规则与方法重载规则相同。
10)构造器是不能继承的!虽说是叫构造方法,但实际上它不是常说的一般方法。
11)子类继承父类,那么子类型构造器默认调用父类型的无参数构造器。
12)子类构造器一定要调用父类构造器,如果父类没有无参数构造器,则必须使用super(有参数的),来调用父类有参的构造器。
为什么子类一定要访问父类的构造器?
因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问一下父类中的构造器。总之,子类中至少会有一个构造器会访问父类中的构造器,且子类中每一个构造函数内的第一行都有一句隐式 super()。
3、super()、super.和 this()、this.
1)this:在运行期间,哪个对象在调用 this 所在的方法,this 就代表哪个对象,隐含绑定到当前“这个对象”。
2)super():调用父类无参构造器,一定在子类构造器第一行使用!如果没有则是默认存在 super()!这是 Java 默认添加的 super()。
3)super.是访问父类对象,父类对象的引用,与 this.用法一致
4)this():调用本类的其他构造器,按照参数调用构造器,必须在构造器中使用,必须在第一行使用,this() 与 super() 互斥,不能同时存在
5)this.是访问当前对象,本类对象的引用,在能区别实例变量和局部变量时,this 可省略,否则一定不能省!
6)如果子父类中出现非私有的同名成员变量时,子类要访问本类中的变量用 this. ;子类要访问父类中的同名变量用 super.
1 package com.boom.test; 2 public class SuperTest { 3 public static void main(String[] args) { 4 ChildrenClass childrenClas = new ChildrenClass(); 5 childrenClas.show(); 6 } 7 8 } 9 //定义个父类 10 class FatherClass{ 11 public int value; 12 public void show(){ 13 value = 100; 14 System.out.println("FatherClass = " + value);//FatherClass = 100 15 } 16 } 17 //子类继承父类 18 class ChildrenClass extends FatherClass{ 19 private int value; 20 21 @Override 22 public void show() { 23 super.show();// 调用父类的show方法 24 value = 200; 25 System.out.println("ChildrenClass = " + value);//ChildrenClass = 200 26 System.out.println("value = " + value);//value = 200 27 System.out.println("value = " + super.value);// 访问父类value = 100 28 } 29 }
4、重载和重写
1)重载:方法名一样,参数列表不同的方法构成重载的方法(多态的一种形式)
①调用方法:根据参数列表和方法名调用不同方法。
②与返回值类型无关。
③重载遵循所谓“编译期绑定”,即在编译时根据 参数变量的类型判断应调用哪个方法。
2)重写:通过类的继承关系,由于父类中的方法不能满足新的要求,因此需要在子类中修改从父类中继承的方法叫重写(覆盖)。
①方法名、参数列表、返回值类型与父类的一模一样,但方法的实现不同。若方法名、参数列表相同,但返回值类型不同会有变异错误!若方法名、返回值类型相同,参数列表不同,则不叫重写了。
②子类若继承了抽象类或实现了接口,则必须重写全部的抽象方法。若没有全部实现抽象方法,则子类仍是一个抽象类!
③子类重写抽象类中的抽象方法或接口的方法时,访问权限修饰符一定要 >= 被重写的抽象方法的访问权限修饰符!
如何重写?
1、访问权限: 子类重写的方法的访问权限必须 >= 父类被重写的方法的权限
2、方法的返回类型:
1) 返回类型是void ,那么必须都是 void。
2) 返回类型 是基本数据类型的话,那么子类和父类的重写的方法必须要一致。
3) 返回类型 是引用数据类型的话,子类重写的方法的返回类型 可以是父类返回类型的 子类型。
3、方法名字必须一致。
4、参数列表:必须一致,如果不一致,那就是重载了。
5、方法的抛出的异常类型:子类重写方法抛出的异常的类型可以是 父类中被重写方法抛出的异常的类型的子类型
1 package com.boom.test; 2 /** 3 * 方法的重写 Override 4 * @author Administrator 5 * 6 */ 7 public class OverrideTest { 8 9 public static void main(String[] args) { 10 Cat cat = new Cat(); 11 cat.sound(); 12 } 13 14 } 15 class Animal{ 16 void sound(){ 17 System.out.println("动物发出声音"); 18 } 19 } 20 class Cat extends Animal{ 21 @Override 22 void sound() { 23 System.out.println("我们一起学猫叫,一起 ~~喵喵喵~~"); 24 } 25 }
静态方法是否可以重写??
不可以,静态方法可以被子类继承,不能被子类重写。
对象的比较 == 和 equals
== :比较两基本类型变量的值是否相等,比较两个引用类型的值即内存地址是否相等,即是否指向同一对象。
equals():两对象的内容是否一致
因为equals 源码也是使用 == 进行判断,一般都需要重写equals方法
重载重载的总结:
5、继承(Extends)
继承:子类对象中包含了所有的父类实例成员属性,并且子类拥有父类的成员并可以在子类中直接访问父类中的成员的过程
语法:
class 继承类名 extends 被继承的类名{
//类体
}
被继承的类名:父类、基类、超类
继承类名:子类、衍生类、派生类
extends:java 关键字。扩展、继承。
两层意思:继承、扩展
继承:子类拥有父类的功能。
扩展:子类中定义了新的功能和属性、子类中重写了父类的方法。
继承优缺点:1, 提高代码复用性;
2, 让类与类之间产生关系,给多态提供前提。
缺:为了让子类继承父类的某些成员,那么会在一定程度上打破封装
Java中支持单继承[单继承:一个子类之只能有一个直接父类],不直接支持多继承,但对C++中的多继承机制进行改良。
多个类可以继承一个父类:
class A{ }
class B extends A{ }
class C extends A{ }
多重( 多层 )继承:一个类只能有一个直接的父类,但是可以有多个间接的父类
class A{ }
class B extends A{ }
class C extends B{ }
多继承:一个子类可以有多个直接父类(Java中不允许,进行改良)在Java中通过“多实现”方式体现
class A{ }
class B{ }
class C extends A,B{ }
多继承存在问题:不直接支持,多个父类中有相同的成员,会产生调用的不确定性。
继承体系:java 的整个类的体系结构,是一个单根的系统。根就是 Object 类
在java 体系中,任何一个类(jdk提供的 + 自定义的),都直接的或者间接的继承了 Object 类。 除了Object 类自身。如果一个类没有显式的直接继承任何一个类,那么该类默认继承 Object(隐式继承)。
继承的疑问?
1、是先有子类,还是先有父类?
答:先有子类的。先定义了子类,然后将子类中公有的部分抽取出来形成的父类。
2、哪个类型更大?表示的对象的范围更大?
答:父类类型描述的对象的范围更大、子类描述的类型更加的具体,功能更强大。子类中的功能和属性往往更多一些
3、子类继承父类的成员变量和成员方法,但不继承父类的构造方法,但不见得可以直接访问(比如,父类私有的属性和方法)
6、static关键字
静态的,只能在类内部使用,可以修饰:属性,方法,内部类。在类加载期间初始化,存在方法区中。
1)静态成员随着类的加载而加载,加载于方法区中,且优先于对象存在。
2)静态修饰的成员:属于类级别的成员,是全体类实例(所有对象)所共享。
3)静态属性:只有一份(而实例变量是每个对象有一份),全体实例共享,类似于全局变量
4)使用类名访问静态变量,以及类名直接调用方法,不需要创建对象。
5)静态方法只能访问静态成员(静态属性和静态方法),非静态方法既可访问静态,也可访问非静态。
6)静态方法中没有隐含参数 this,因此不能访问当前对象资源。也不能定义 this 和 super关键字,因为静态优于对象先存在。
7)非静态方法省略的是 this,静态方法省略的是类名(在同一类中),即直接使用属性和方法。
静态代码块与代码块
静态代码块:在类加载的时候,执行,并且仅执行一次。且优先于主函数,用于给类初始化。对类的静态成员变量初始化,并执行静态代码块。
作用:如果某些代码希望仅执行一次,可以在这里面进行,还有对静态成员变量初始化。
代码块(构造代码块):给所有对象进行统一初始化,且优先于构造器执行;而构造器是给对应的对象进行初始化。
static关键字使用注意点:
1, 静态方法只能访问静态成员;
2, 静态方法中不可以使用this或者super关键字(this和super是赖于某个对象的);
3, 主函数是静态的 (由jvm 负责调用执行。不需要创建所在类的对象就可以直接运行)
7、final关键字(最终的,可以修饰:类、方法、变量(成员变量和局部变量)
1)final 修饰的类:不能再继承。
2)final 修饰的方法:不能再重写。
3)final 的方法和类,阻止了动态代理模式!动态代理模式广泛的应用在: Spring 、Hibernate 、Struts2
4)企业编程规范:不允许使用 final 的方法和类!
5)final 的变量:final 变量只能初始化一次(赋值一次,且方法中不能有给 final 变量赋值的语句!因为方法可被调用多次!),不能再修改!也可在方法参数列表添加 final。
6)static final 共同修饰的叫常量,常量:public static final double PI = 3.14; PI 是直接数的代名词,是名字。字面量(==直接量):直接写出数值 3.1415926535897 宏观说:字 面量和常量都称为常量!
8、多态(polymorphism)
1)多态指的是同一个方法调用,由于对象不同可能会有不同的行为。
2)多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
3)父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
多态的优缺点:优点:提高程序可扩展性和后期可维护性
缺点:通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有方法
多态的应用:1:父类类型作为参数,传递的是子类对象。
2:父类类型作为方法的返回类型,返回的是子类对象。
1 package boom.oop02; 2 3 public class PolymTest { 4 5 public static void main(String[] args) { 6 // 创建动物类对象 7 Animal animal = new Animal(); 8 AnimalSonud(animal);//调用动物自己 9 10 Dog dog = new Dog(); 11 AnimalSonud(dog); 12 AnimalSonud(new Cat()); 13 14 AnimalSonud(new Trigger()); 15 16 } 17 // 定义动物发出声音的方法,把动物类传参进来 18 static void AnimalSonud(Animal animal){ 19 animal.sound(); 20 } 21 } 22 // 创建动物类 父类 23 class Animal{ 24 public void sound(){ 25 System.out.println("动物发出了声音……"); 26 } 27 } 28 29 // 猫继承了动物类 30 class Cat extends Animal{ 31 public void sound() { 32 System.out.println("猫发出了喵喵喵……"); 33 } 34 } 35 36 class Dog extends Animal{ 37 public void sound() { 38 System.out.println("旺财发出了旺旺……"); 39 } 40 } 41 42 class Trigger extends Animal{ 43 public void sound() { 44 System.out.println("虎啸震山谷……"); 45 } 46 }
1 package com.test; 2 /** 3 * 多态的综合应用:人去演奏乐器,不同的乐器发出不同的声响 4 * 大鼓Drum,吉他Guitar,钢琴Piano,小号Trumpet 5 * @author Administrator 6 * 7 */ 8 public class Code { 9 10 public static void main(String[] args) { 11 12 Person person = new Person(); 13 14 Drum drum = new Drum(1000, "战鼓"); 15 person.play(drum); 16 Piano piano = new Piano(2000, "钢琴"); 17 person.play(piano); 18 Guitar guitar = new Guitar(2000, "吉他"); 19 person.play(guitar); 20 Trumpet trumpet = new Trumpet(2000, "军号"); 21 person.play(trumpet); 22 23 24 // Instrument instrument = new Drum(12000, "fas"); 25 // instrument.sound(); 26 // 27 28 29 } 30 // void paly(Instrument instrument){ 31 // instrument.sound(); 32 // } 33 // 34 } 35 36 // 定义person类 37 class Person{ 38 // 定义人具有演奏乐器的方法 39 void play(Instrument instrument){ 40 instrument.sound(); 41 } 42 } 43 44 45 // 定义乐器类 46 class Instrument{ 47 // 乐器的属性:单价 乐器名 48 private int price; 49 private String name; 50 // 定义无参有参的构造方法,进行乐器的初始化 51 public Instrument() { 52 } 53 public Instrument(int price, String name) { 54 super(); 55 this.price = price; 56 this.name = name; 57 } 58 59 // getter setter方法 60 public int getPrice() { 61 return price; 62 } 63 public void setPrice(int price) { 64 this.price = price; 65 } 66 public String getName() { 67 return name; 68 } 69 public void setName(String name) { 70 this.name = name; 71 } 72 // 定义乐器类发出声音的方法 73 void sound(){ 74 // 空实现 75 } 76 } 77 78 class Drum extends Instrument{ 79 80 public Drum(int price, String name) { 81 super(price, name); 82 } 83 84 @Override 85 void sound() { 86 System.out.println(getName() + " 被用力的敲击了几下,发出了 ~~~~咚咚咚~~~的声音!"); 87 } 88 89 } 90 91 class Piano extends Instrument{ 92 public Piano(int price, String name) { 93 super(price, name); 94 } 95 96 @Override 97 void sound() { 98 System.out.println(getName() + " 被手指拨弄了几下,发出了 ~~~叮当叮叮的~~~的声音!"); 99 } 100 } 101 102 class Trumpet extends Instrument{ 103 104 public Trumpet(int price, String name) { 105 super(price, name); 106 } 107 108 @Override 109 void sound() { 110 System.out.println(getName() + " 被吹了几下,发出了 ~~~~嘟嘟嘟~~~的声音!"); 111 } 112 } 113 114 class Guitar extends Instrument{ 115 public Guitar(int price, String name) { 116 super(price, name); 117 } 118 119 @Override 120 void sound() { 121 System.out.println(getName() + " 被弹奏了几下,发出了 ~~~~当当当~~~的声音!"); 122 } 123 }
多态的转型:自动转型 强制转型
自动向上类型转换:子类对象当父类类型来使用。自动的一定是安全的。父类有的功能,子类一定有。
当我们需要使用子类中特有的方法的时候,需要强制向下
强制向下类型转换。这种转换是强制的,不是安全的。这种转换只有被转换的对象的确是需要转换的类型才可以转换成功
注意:只有对象的实际类型是你强制转换的类型的时候,才可以转换成功。不然运行期会抛出错误
instanceof:关键字、运算符。左边操作数的对象的类型 和 右边操作数的类型 必须存在继承关系才可以使用 instanceof 进行判断
二元运算符:作用:用来判断 一个对象 是否是某种类型的实例的。
用法:操作数1 instanceof 操作数2
操作数1:必须是一个对象
操作数2:必须是一种类型
返回 boolean
如果 操作数1 对象 是 操作数2 类型的实例 返回 true 否则返回 false。