面向对象特征
封装
将类的某些信息隐藏在内部(通过访问权限修饰符来实现),不让外部直接对其访问,只提供一些方法对隐藏的信息进行访问
public class Dog {
//隐藏类的属性
private String name;
public Dog() {
}
public Dog(String name) {
if(name!=null){
this.name = name;
}
}
private void eat(){
}
//提供特定的方法,对隐藏成员进行访问
public void setName(String name){
if(name!=null){
this.name = name;
}
}
public String getName(){
return this.name;
}
}
封装的好处:隐藏类的实现细节
方便加入控制语句
方便修改实现
只能通过规定方法访问
设计模式:解决一类问题的解决方案(模式)
单例模式-->让一个类在一个程序中,只能创建一个对象
public class WindowDemo {
//接收唯一的一个对象
private static WindowDemo windowDemo = null;
/*
将构造方法设置为私有权限,在其他类中不能随便使用.
*/
private WindowDemo() {
}
//向外界提供方法,获取唯一的对象
public static WindowDemo getWindow() {
//控制生成对象数量
if (windowDemo == null) {
windowDemo = new WindowDemo();
}
return windowDemo;
}
}
public class TestWindow {
public static void main(String[] args) {
//new WindowDemo();
//new WindowDemo();
WindowDemo windowDemo1 = WindowDemo.getWindow();
WindowDemo windowDemo2 = WindowDemo.getWindow();
System.out.println(windowDemo1);
System.out.println(windowDemo2);
}
}
我们可以将构造方法设置为私有的,那么就无法在其他类中创建对象
我们可以定义一个静态方法,然后通过类去调用该静态方法,从而实现单例模式-->让一个类在一个程序中,只能创建一个对象
继承
从已有的类中派生出新的类,新的类拥有已有类的属性和行为,并且可以扩展新的功能
继承是面向对象不可缺少的设计思想,体现了代码的复用性,提高了代码的可扩展性
-
在java中使用extends关键字表示继承关系
-
java不支持多继承,单继承使得java继承关系很简单,一个类只有一个直接父类
-
继承的子类可以调用父类所有的非私有的方法和属性
继承的传递性:
C类从B类继承,B类又从A类继承
那么C类就具有B类和A类的所有非私有的属性和方法
当一个类没有继承任何一个类时,jvm会默认让其继承Object类,Object类时java为所有类提供的基类
继承的构造方法:new子类对象,在调用构造方法时,从上到下调用,先初始化父类信息
使用super关键字在子类构造方法第一行默认执行,调用父类无参构造方法
误区:super调用父类的成员变量或者方法时,并不是创建父类对象,而是将父类的信息加载到子类对象的存储中
方法的重写(OverRide):当父类的方法不能满足子类需求时,可以对方法进行重写
在子类中可以根据需要对从基类中继承来的方法进行重写
方法重写规则:
-
方法名相同、参数列表相同
-
返回值类型相同
-
访问权限不能小于父类权限
ps:构造方法、静态方法不能重写,成员变量不存在重写
@Override:是java中的一个注解标签(是一种标记、记号)
添加此注解标签表示此方法是从父类重写来的,就会对其进行语法验证
Override(重写) overload(重载)
继承的优缺点:
优点:提高了代码的复用性,提高了代码的维护性
缺点:继承让类与类之间产生了关系,类的耦合性也增加了,当父类发生变化时,子类也需要发生变化,削弱了子类的独立性
抽象类
也是类 抽象(概念)
抽象类是用abstract修饰,抽象类可能包含抽象方法,也可能不包含抽象方法,如果一个类中没有包含足够的信息(抽象方法)来描绘一个具体的对象,这样的类就是抽象类
抽象类不能创建对象(因为其中包含抽象方法),其他功能则与类相同(成员变量、成员方法、构造方法)
抽象类一般都是位于体系结构的上层,用来定义功能
public abstract class Person {
String name;
public Person(){
}
public void eat(){
System.out.println("人吃饭");
}
/*
abstract 修饰的方法是抽象方法,没有方法体
*/
public abstract void speak();
}
如果一个类继承了抽象类,要么重写抽象类中的全部抽象方法,要么继承的类也声明为抽象类
/*
如果一个类继承了抽象类,要么重写抽象类中所有抽象方法,要么将此类也声明为抽象类
*/
//public abstract class Chinese extends Person{
public class Chinese extends Person{
@Override
public void speak() {
System.out.println("中国人说汉语");
}
}
抽象方法:只有声明,没有具体的实现
在一些比较靠顶层的类,它的实现与子类大多数不同,此时没必要在顶层实现,只需要声明功能即可
抽象方法必须使用abstract关键字进行修饰
多态
同一个行为,使用不同的对象获得不同的状态
多态存在的三个必要条件:
-
要有继承(包括接口的实现)
-
要有重写
-
父类引用指向子类对象
可以先创建一个抽象类
public abstract class Animal {
int age = 10;
public Animal(){
}
public abstract void eat();
public void sleep(){
System.out.println("动物睡");
}
public static void play(){
System.out.println("动物玩");
}
}
再创建一些类去继承并且重写该抽象类的方法
public class Dog extends Animal{
int age = 15;
public Dog(){
}
@Override
public void eat() {
System.out.println("Dog重写Animalh中的eat()---狗吃骨头");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
测试方法
public class Test {
public static void main(String[] args) {
Dog xh = new Dog();
/*
编译期间 a.eat() a的类型是Animal类,调用的是抽象的eat()
运行期间 a执向的是一个Dog对象,运行的是Dog中重写的eat()
针对于非静态成员方法:
编译期间看左边(写代码时)
运行期间看右边
*/
Animal a = new Dog();
a.eat();//Dog重写Animalh中的eat()---狗吃骨头
a.sleep();//动物睡,因为在子类中没有重写该方法,所以调用的还是父类的方法
/*
针对静态方法
编译期间看左边
运行期间还是看左边
*/
a.play();//静态方法无法重写,所以调用的依然是父类的方法
/*
针对成员变量
编译期间看左边
运行期间还是看左边
*/
System.out.println(a.age);//成员变量不存在重写,所以还是父类的
}
}
多态的好处:提升代码的扩展性,我们可以只写一个方法,给方法传入父类的参数,这样我们编译起来也显得代码很简洁
public class Test3 {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
Test3 t = new Test3();
t.feedAnimal(dog);
t.feedAnimal(cat);
}
/*
喂动物
*/
public void feedAnimal(Animal animal){
animal.eat();
}
}
反例:如果没有多态,我们的代码就会显得很多,造成了冗余
public static void main(String[] args) {
/*
此程序扩展性不好 ,每添加一个动物类,新增一个方法
*/
Dog dog = new Dog();
Cat cat = new Cat();
Test2 t = new Test2();
t.feedDog(dog);
t.feedCat(cat);
}
/*
喂狗
*/
public void feedDog(Dog dog){
dog.eat();
}
/*
喂猫
*/
public void feedCat(Cat cat){
cat.eat();
}
}
多态转型:
自动转型:子 继承 父
向上转型 子类型 自动转为 父亲类型
Animal dog = new Dog();
优点:父类引用子类对象,提升程序的扩展性
缺点:父类不能调用子类中特有的方法
向下转型 父亲类型 转为 子类自己的类型
为了使用子类中特定的方法
public void feedAnimal(Animal animal){
animal.eat();
//判断animal中实际传入的类型是什么
// 父类引用 instanceof 具体的子类类型
//instanceof 判断父类引用实际表示的对象 是不是 指定类型
System.out.println(animal instanceof Dog);
if(animal instanceof Dog){
Dog dog = (Dog)animal;
dog.play();
}
}