------- android培训、java培训、期待与您交流!----------
面向对象
一、基本概述
定义:面向对象(Object Oriented,OO)是软件开过过程中使用一种思维方式 。
面向过程:强调功能行为,关注完成的过程;
面向对象:将功能封装进对象,强调具备了功能的对象,不关注过程;
面向对象与面向过程都是一种思想,面向对象是基于面向过程的。
面向对象的特点:
是一种更符合人们思考习惯的思想。
可以将复杂的事情简单化。
将程序由执行者转换成了指挥者。
面向对象完成需求:
明确开发功能需求。
查找具有该功能的类。
如果不存在满足功能的类,则定义这样的类。
创建该类对象,使用对象完成功能。
面向对象的三大特征:
封装(encapsulation)
继承(inheritance)
多态(polymorphism)
类与对象概述
类定义:具有相同特征(属性)和行为(功能)的一类事物的抽象。
比如:人类有身高,体重等属性,有说话,打球等行为。
动物类有年龄,性别等属性,有吃饭,睡觉等行为。
对象定义:类的实体
比如:人类是类的定义,张三李四便是人类的实体对象。
水果类是类的定义,苹果橘子是水果类的实体对象。
类与对象的关系:
类是抽象概念,对象是类的具体实例。
一个类可以有多个对象。一个对象只属于一个类。
对象创建格式:
数据类型 变量名(对象名) = new 数据类型(参数);
对象的使用:
成员变量的访问:
对象名.属性名
成员函数的调用:
对象名.函数名(参数)
举例:Phone类
代码实现:
/* 手机事物: 属性: 品牌(brand) , 颜色(color) , 价格(price) .... 行为: 打电话(call) , 发短信(sendMessage) , 玩游戏(playGame) ... 手机类: 成员变量: 品牌(brand) , 颜色(color) , 价格(price) 成员方法: 打电话(call) , 发短信(sendMessage) , 玩游戏(playGame) */ class Phone { // 成员变量 // 品牌 String brand = "三星"; // 颜色 String color = "白色"; // 价格 int price = 998 ; // 成员方法 // 打电话 public void call(String name){ System.out.println("给" + name + "打电话"); } // 发短信 public void sendMessage(String name){ System.out.println("给" + name + "发短信"); } // 玩游戏 public void playGame(){ System.out.println("玩游戏...."); } }
类的使用代码实现
// 手机类 class Phone { // 成员变量 String brand ; // 品牌 String color ; // 颜色 int price ; // 价格 // 成员方法 // 打电话 public void call(String name){ System.out.println("给" + name + "打电话"); } // 发短信 public void sendMessage(String name){ System.out.println("给" + name + "发短信"); } // 玩游戏 public void playGame(){ System.out.println("玩游戏...."); } } // 测试类 class PhoneDemo { public static void main(String[] args){ // 创建手机对象 Phone p = new Phone(); // 输出所有的成员变量 System.out.println(p.brand + "---" + p.color + "----" + p.price); // 给成员变量赋值 p.brand = "诺基亚"; p.color = "黑色"; p.price = 199 ; // 输出所有的成员变量 System.out.println(p.brand + "---" + p.color + "----" + p.price); // 调用方法 p.call("刘亦菲"); p.sendMessage("刘亦菲"); p.playGame(); } }
成员变量与局部变量概述
成员变量:
定义位置:类中,整个类中均可以访问。
内存:成员变量随着对象的建立而建立,存在于对象所在的堆内存中。
默认值:成员变量有默认值。
回收:随着对象的回收而回收。
局部变量:
定义位置:定义域局部范围,如函数内,语句内等。
内存:局部变量存在于栈内存中。
默认值:没有默认值。
回收:随着作用域结束而回收,通常为语句或函数范围。
变量访问原则:就近原则
代码实现:
class Demo { int b ; int a = 40 ; public void show(){ // 错误的: 可能尚未初始化变量a // int a ; // System.out.println(a); int a = 30 ; System.out.println(a); } } class VariableDemo { public static void main(String[] args){ // 创建Demo对象 Demo d = new Demo(); // 调用show方法 d.show(); // 获取b System.out.println(d.b); } }
三大特征之封装
概述:
定义:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
优点:
将变化隔离
便于使用
提高重用性
原则:提高安全性
将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。
private关键字:
是一个权限修饰符。
用于修饰成员(成员变量和成员函数)
被私有化的成员只在本类中有效。
常用方式:将成员变量私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全性。
this关键字:
定义:this代表其所属对象的引用。没有实例对象,this就没有意义。
使用:
当在函数内需要用到调用该函数的对象时,就用this
局部变量隐藏成员变量时,使用this区分。
构造函数中第一行,用来调用本类其他重载的构造函数。
代码实现:封装学生类
// 学生类 class Student { // 定义成员变量 private String name ; // 姓名 private int age ; // 年龄 private String sex ; // 性别 // get和set方法 public void setName(String name){ this.name = name ; } public String getName(){ return name ; } public void setAge(int age){ this.age = age ; } public int getAge(){ return age ; } public void setSex(String sex){ this.sex = sex ; } public String getSex(){ return sex ; } } // 测试类 class StudentDemo { public static void main(String[] args){ // 创建学生对象 Student s = new Student() ; // 给成员变量赋值 s.setName("小花"); s.setAge(18); s.setSex("女"); // 输出成员变量 System.out.println(s.getName() + "----" + s.getAge() + "----" + s.getSex()); } }
三大特征之继承
概述:定义:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
这多个类称为子类,单独这个类称为父类或者超类。子类可以直接访问父类中非私有的成员变量与成员方法。
格式:通过 extends 关键字让类与类之间产生继承关系
class SubDemo extends Demo{}
优点:继承的出现提高了代码的复用性。
继承的出现让类与类之间产生了关系,是多态的前提之一。
弊端:使类与类之间产生了更强的耦合性
代码实现:
class Demo5 { public static void main(String[] args) { Cat cat = new Cat(); cat.eat(); Dog dog = new Dog(); dog.eat(); System.out.println(cat.name); //System.out.println(cat.age); } } class Animal { String name = "四不像"; private int age = 20; public void eat(){ System.out.println("吃了"); } public void sleep(){ System.out.println("睡了"); } } class Cat extends Animal { public void catchMouse(){ System.out.println("猫抓老鼠的方法"); } } class Dog extends Animal{ } class Person extends Animal{ }
特点:
java只支持单继承不支持多继承。
java支持多层继承。
任何类都直接或者间接继承自Object类。
注意事项:
不要为了某个功能而去继承,需要满足”is a”的关系。
代码时下:
class Demo6 { public static void main(String[] args) { Manager m = new Manager(); m.eat(); System.out.println(m.hashCode()); Boss boss = new Boss(); boss.eat(); boss.keepMoney(); } } class Animal { String name = "四不像"; private int age = 20; public void eat(){ System.out.println("吃了"); } public void sleep(){ System.out.println("睡了"); } } class Cat extends Animal { public void catchMouse(){ System.out.println("猫抓老鼠的方法"); } } class Dog extends Animal { public void keepMoney() { System.out.println("钱看住了!"); } } class Person extends Animal { } class Manager extends Person { } //不同种类的继承是不应该存在,不能为了某个功能而继承不同种类的类。 //继承时必须符合"is a"的关系。 //如果仅仅是需要里边的某个功能的话,可以时候后边学习的"实现" class Boss extends Dog { }
继承后的成员特点:
成员变量:访问满足就近原则
局部变量>成员变量>父类成员变量>父类的父类
代码实现
class Demo7 { public static void main(String[] args) { Cat cat = new Cat(); cat.catchMouse(); //System.out.println(cat.name); } } class Animal { String name = "哺乳动物"; private int age = 20; public void eat(){ System.out.println("吃了"); } public void sleep(){ System.out.println("睡了"); } } class Cat extends Animal { String name = "kitty"; public void catchMouse(){ String name = "Tom"; System.out.println("我是"+name); System.out.println("猫抓老鼠"); //super.eat(); super.eat(); } } class Dog extends Animal { }
成员方法:
子类可以直接使用父类的非私有方法。
当子父类方法一样时,方法重写。
代码实现:
class Demo8 { public static void main(String[] args) { Cat cat = new Cat(); cat.eat(); //cat.sleep(); //cat.catchMouse(); } } class Animal { public void eat(){ System.out.println("吃了"); } public void sleep(){ System.out.println("睡了"); } } class Cat extends Animal { public void catchMouse(){ System.out.println("猫抓老鼠"); //super.eat(); super.eat(); eat(); this.eat(); } public void eat(){ System.out.print("喵,"); super.eat(); } }
构造方法:
构造方法不继承,子类的构造默认调用父类构造。
父类构造方法负责对成员变量初始化供子类对象使用,而不是创建父类对象。
父类没有无参构造时,子类需要手动调用其他父类构造。
代码实现
class Demo10 { public static void main(String[] args) { Cat cat = new Cat("Tom"); //Animal a = new Animal(); System.out.println(cat.getName()); //Cat cat2 = new Cat(); //System.out.println(cat2.getName()); } } class Animal { private String name = "哺乳动物"; public Animal(){ System.out.println("我是父类Animal中的空参构造"); } public Animal(String name){ this.name = name; System.out.println("我是父类Animal中的有一个参数的构造"); } public void setName(String name) { this.name = name; } public String getName() { return name; } } class Cat extends Animal { public Cat(){ //super(); super("庞中华"); System.out.println("我是子类Cat中的空参构造"); } public Cat(String name){ //super(); super(name); System.out.println("我是父类Animal中的有一个参数的构造"); } }
方法重载与方法重写:
重载:一般是在同一个类中,(但是也有可能在子父类中包含重载关系)
规则:
方法名相同
参数列表不同:类型不同,个数不同,顺序不同
与其他内容都无关
重写:一定涉及两个或两个以上的类,并且有子父类关系
规则:
访问权限:相同 或者 子类访问权限大于父类访问权限
函数名:相同
参数列表:相同
返回值类型:
void符合基本类型的规律
基本数据类型:必须相同
引用数据类型:相同 或者 不同时,父类返回值是子类返回值的父类是可以的。(子类返回值小于父类)
静态方法只能覆盖静态方法
代码实现:
System.out.println("子类重写的静态方法");
class Demo9 { public static void main(String[] args) { Cat cat = new Cat(); cat.eat(); //cat.eat("fish"); cat.sleep(); } } //访问权限 默认的<public class Animal { public Fu eat(){ System.out.println("吃了"); return new Fu(); } public static void sleep(){ System.out.println("父类的静态方法"); } /* public void eat(String food){ System.out.println("吃了"+food); } */ } class Cat extends Animal { public Zi eat(){ System.out.println("喵,吃了"); return new Zi(); } public static void sleep(){ } } class Fu{} class Zi extends Fu{}
this和super关键字
this:
方式一:用来访问父类存储空间的成员
方式二:用来在子类的构造方法中调用父类的构造方法
super:
方式一:用来访问子类自己的成员
方式二:用来在本类的构造方法中调用本类的其他构造方法
this与super调用构造方法都必须放在第一行
子父类构造方法设计原则:至少有一个构造必须先访问父类构造,在父类构造完毕之后,再访问本类构造
代码实现:
class Demo11 { public static void main(String[] args) { Cat cat = new Cat("kitty"); //cat.eat(); cat.catchMouse(); } } class Animal { String name = "哺乳动物"; public Animal(){ System.out.println("我是父类Animal中的空参构造"); } public Animal(String name){ this.name = name; System.out.println("我是父类Animal中的有一个参数的构造"); } public void eat(){ System.out.println("我是父类中的eat方法"); } } class Cat extends Animal { //String name = "Tom"; int age = 10; public Cat(){ //super(); System.out.println("我是子类Cat中的空参构造"); } public Cat(String name){ super(name); System.out.println("我是父类Animal中的有一个参数的构造"); } public Cat(int age) { this.age = age; } public Cat(String name,int age) { //super(name); //仅仅给年龄赋值,不管姓名时 this(age); } public void eat(){ System.out.println("我是子类中的eat方法"); } public void catchMouse(){ System.out.println("我是子类中的catchMouse方法"+super.name); super.eat(); } }
final关键字:最终修饰符
修饰类:类无法被继承
修饰方法:方法无法被重写
修饰变量:
成员变量:
必须被赋值,只能赋值一次。
赋值动作需要在对象创建完成之前执行
局部变量:
只能赋值一次
代码实现:
class Demo { public static void main(String[] args) { Cat cat = new Cat("kitty"); //Cat cat = new Cat(); //cat.name = "Tom"; System.out.println(cat.name); cat.myMethod(); cat.myMethod2("石家庄"); cat.myMethod3(28); Person p = new Person("段正淳",30); //0x1234 cat.myMethod4(p); } } //final class Animal 被final修饰的类无法被继承 class Animal { public final void method(){} } class Cat extends Animal { /*子类无法重写父类中final修饰的方法 public void method(){ System.out.println("我是子类的方法"); } */ //final String name = "Tom"; final String name; //public Cat(){} //如果同时还存在空参不给name赋值的构造,则会报错:可能尚未初始化。 public Cat(String name){ this.name = name; } //定义方法,测试final修饰局部变量 public void myMethod(){ final String city = "北京"; //city = "张家口"; final修饰的变量只能赋值一次 System.out.println(city); } public void myMethod2(final String city){ //city = "北京"; //city = "张家口"; final修饰的变量只能赋值一次 System.out.println(city); } public void myMethod3(final int age){ //age = 30; System.out.println(age); } public void myMethod4(final Person p){//0x1234 p.name = "段延庆"; p.age = 40; //p = new Person("段誉",18); //0x2234 } }
三大特征之多态
概述:
定义:某一种事物的多种形态。
前提:
必须多态的两个类间存在关系(继承/实现)
要有方法覆盖操作,否则没有意义
java中父类引用指向子类对象
代码实现:
class Demo2 { public static void main(String[] args) { Animal a = new Animal(); //动物是动物 Cat c = new Cat(); //猫是猫 Animal a2 = new Cat(); //猫是动物 //Cat c2 = new Animal(); //动物是猫 } } class Animal { } class Cat extends Animal { }
多态的优点及特点:
优点:
开发当中要符合开闭原则:对修改关闭,对扩展开放。
多态的存在提高了程序的扩展性和后期可维护性。
特点(规则):
成员变量:
编译期:看左边 / 看父类
运行期:看左边 / 看父类
成员函数:
编译期:看左边 / 看父类
运行时:看右边 / 看子类
只有在调用方法时,检查子类是否有重写,子类重写调用子类重写的方法,其余所有内容均看父类类型。只有调用方法看子类。
代码实现:
class Demo3 { public static void main(String[] args) { //使用多态的方式创建一个Cat对象 Animal a = new Cat(); //System.out.println(a.name); a.methodFu(); //a.methodZi(); } } class Animal { //String name = "花花"; public void methodFu(){ System.out.println("我是父类中的方法"); } } class Cat extends Animal { String name = "曹操"; /*多态时,调用父类没有的子类方法不可以 public void methodZi(){ System.out.println("我是子类中的方法"); } */ //子类重写父类的方法 public void methodFu(){ System.out.println("我是子类中重写的父类方法"); } }
向上向下转型:
向上转型:引用变量为父类时,子类实例对象可以自动提升为父类类型 子↑父
向下转型:可以使用强制类型转换,完成向下转型 父↓子
代码实现:
class Demo4 { public static void main(String[] args) { //第一次调用 Animal a = new Cat(); method(a); //第二次调用 Cat cat = new Cat(); method(cat); //第三次调用 Cat cat2 = new Cat(); method2(cat2); //使用第四调用的方法演示向下类型转换 Cat cat3 = new Cat(); method3(cat3); Animal a2 = new Animal(); method3(a2); } //第一次调用 Animal a >> Animal b >> Animal c //第二次调用 Cat cat >> Animal b >> Animal c public static void method(Animal b){ Animal c = b; c.methodFu(); } //第三次调用 Cat cat >> Animal b public static void method2(Animal b){ b.methodFu(); } //第四次调用 Cat cat >> Animal b >> Animal c >> Cat d(此步骤为强转) 这样是可以的 对象原本就是Cat可以强转成Cat //Animal a2 >> Animal b >> Animal c >> Cat d(此步骤为强转) 这样是不可以的 对象原本不是Cat不能强转成Cat public static void method3(Animal b){ Animal c = b; //c.methodZi(); 父类类型没有methodZi方法 Cat d = (Cat)c; d.methodFu(); d.methodZi(); //强转成子类对象后,可以调用子类对象自己的方法 } } class Animal { String name = "kitty"; public void methodFu(){ System.out.println("我是父类中的方法"); } } class Cat extends Animal { public void methodFu(){ System.out.println("我是子类中重写父类的方法"); } public void methodZi(){ System.out.println("我是子类中的特有方法"); } } class Dog extends Animal { public void methodFu(){ System.out.println("我是子类中重写父类的方法"); } public void methodZi(){ System.out.println("我是子类中的特有方法"); } }
抽象类:
抽象定义:
抽象就是从多个事物中将共性的,本质的内容抽取出来。
例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。
抽象类定义:
包含抽象方法的类就是抽象类。
抽象类不一定包含抽象方法。
类/抽象类不一定包含方法。
抽象方法定义:抽象类可以有非抽象方法。
多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
抽象声明格式:
声明一个方法是抽象的:在方法前加abstract关键字
声明一个类是抽象的:在类前加abstract关键字
代码实现:
class Demo9 { public static void main(String[] args) { System.out.println("Hello World!"); } } abstract class Animal { //public abstract void eat(); /*public void sleep(){ System.out.println("睡"); } */ }
抽象类的特点:
抽象类无法实例化
抽象类通过多态的形式创建其子类实例对象
子类需要将抽象父类的抽象方法均覆盖才可以实例化,否则依然是抽象类
抽象类强制子类必须实现抽象方法
代码实现:
class Demo10 { public static void main(String[] args) { Animal animal = new Cat(); //Animal animal = new BoSiCat(); } } abstract class Animal { public abstract void eat(); public abstract void sleep(); } abstract class Cat extends Animal { /* public void eat() { System.out.println("吃鱼!"); } */ //public abstract void eat(); public void sleep(){ System.out.println("睡了"); } } class BoSiCat extends Cat { public void eat() { System.out.println("吃鱼!"); } }
接口:
比抽象类更抽象的表现形式
抽象类可以有非抽象方法接口中全部必须是抽象方法
格式:
定义接口:interface XX {}
使用接口:class YY implements XX{} 类实现接口
代码实现:
class Demo11 { public static void main(String[] args) { MyInterface mi = new MyClass(); mi.method(); } } interface MyInterface { public abstract void method(); } class MyClass implements MyInterface { public void method() { System.out.println("我是类中重写的接口方法"); } }
接口的成员特点:成员变量与成员函数均为固定的修饰符!
构造方法:没有!
public static final XXX xxx = yyy; >>定义一个常量
成员变量:public static final
成员方法:public abstract
代码实现:
class Demo13 { public static void main(String[] args) { MyInterface mf = new MyClass(); System.out.println(MyInterface.age); } } interface MyInterface { String name = "杨幂"; int age = 28; public abstract void method(); } class MyClass implements MyInterface { public void method(){ System.out.println("abc"); } }
内部类
概念:内部类又叫内置类或者嵌套类。即在类中定义的另外一个类。是一个相对概念。
访问特点:
内部类可以直接访问外部类中的成员,包括私有成员。
而外部类要访问内部类中的成员必须要建立内部类的对象。
分类:
成员内部类
局部内部类,匿名内部类属于局部内部类
创建成员内部类对象的格式:
Outer.Inner x = new Outer().new Inner();
记忆方式:对比成员变量与成员函数
访问成员变量:对象.属性
调用成员方法:对象.方法名()
创建成员内部类对象: 对象.new 内部类(参数)
代码实现:
public class Demo11 { public static void main(String[] args) { //定义一个内部类引用变量 //Outer.Inner x //创建一个外部类对象 //Outer out = new Outer(); //通过一个外部类对象创建其内部类对象 //out.new Inner(); Outer.FieldInner x = new Outer().new FieldInner(); x.inMethod(); Outer out = new Outer(); //访问成员变量 String name = out.name; System.out.println(name); //调用成员方法 out.method(); //创建成员内部类对象 Outer.FieldInner inner = out.new FieldInner(); //Outer.FieldInner inner = new out.FieldInner(); 错误的格式,会将out.误认为包名 inner.inMethod(); } } class Outer { String name = "梁洛施"; //成员内部类 class FieldInner { //String name = "梁家辉"; public void inMethod(){ //String name = "梁朝伟"; System.out.println(name); } } public void method(){ System.out.println("我是外部类的一个普通方法"); } /* public void outMethod(){ //局部内部类 class MethodInner { } } */ }
局部内部类:内部类定义在方法内。
无法使用Outer.Inner进行访问。
访问格式:在所在方法内创建对象进行方法调用
同时可以访问所在局部中的局部变量,但必须是被final修饰的。
必须先定义再使用。
代码实现:
class Demo14 { public static void main(String[] args) { Outer out = new Outer(); out.outMethod(); } } class Outer { String name = "梁洛施"; public void outMethod(){ final String name = "梁咏琪"; //局部内部类 class MethodInner { public void method(){ System.out.println("我是局部内部类的方法"); System.out.println(name); } } MethodInner mi = new MethodInner(); mi.method(); } }
匿名内部类:
在通过简写形式定义一个没有类名的类。
在创建一个对象。
匿名内部类即将匿名定义类与创建对象的动作一起完成。
匿名内部类属于局部内部类。
定义格式:
匿名内部类需要先定义再使用。
匿名内部类是一种多态的表现形式。
new 类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)};
使用场景:
1、内部类效率更高。
2、通常在使用接口类型参数的方法上,并该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
3、增强阅读性。
代码实现:
class Demo16 { public static void main(String[] args) { //以前有名字的类:第一步定义有名字的类 第二步创建对象,使用对象 //有名字的对象 有名字的类 Fu 对象名 = new 类名(); 对象名.method(); //没名字的匿名对象 有名字的类 new 类名().method(); System.out.println("==============================================="); //有名字的对象 没有名字的类 Fu noNameObject = new Fu() { public void method() { System.out.println("我是匿名内部类1重写的父类方法"); } }; noNameObject.method(); //没有名字的对象 没有名字的类 new Fu() { public void method() { System.out.println("我是匿名内部类2重写的父类方法"); } }.method(); } } abstract class Fu { public abstract void method(); } class 类名 extends Fu { public void method() { System.out.println("我是子类重写的父类方法"); } }