面向对象总结
面向对象的思想特点:
1.更符合现实生活思想和行为习惯;
2.角色发生了变化,从执行者变成了指挥者;
3.让复杂的事情简单化;
面向对象的三大特征:
1.封装
2.继承
3.多态
一.封装
1.封装知识点
什么是封装:
将一个类的成员变量私有化(使用private关键字修饰),外界不能够直接访问,可以通过一些公共的方法(set/get...)间接的访问!
this关键字:代表当前类对象的地址值引用
this关键字的目的:为了区分成员变量和局部变量,如:this.成员变量或this.局部变量
构造方法的特点:
1.方法名与类名相同
2.没有具体返回值类型
3.连void都没有
构造方法的书写格式:
权限修饰符 方法名(方法名与类名相同)(){//无参构造}
构造方法的作用:
给对象的成员进行数据初始化!
构造方法怎么重载?
无参构造方法
有参构造方法
注意:在写一个类的时候,如果没有提供无参构造方法,系统默认提供无参构造方法!
如果开发者提供了有参构造方法,系统就不会提供无参构造方法,所以建议给出无参构造方法!
类的组成:成员变量,构造方法,成员方法
成员方法:
有具体返回值类型的方法
带形式参数
不带形式参数
没有具体返回值类型的方法
带形式参数
不带形式参数
2.封装的应用
/*
使用一个标准的类描述学生事务
属性:姓名,年龄,性别
行为:学习,玩游戏....
*/
public class Student {
private String name;
private int age;
private String sex;
//无参构造方法
public Student() {
super();
}
//有参构造方法(与无参构造方法构成重载)
public Student(String name, int age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
//get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
//学生的学习方法
public void study() {
System.out.println("study...");
}
//学生的玩游戏方法
public Void playGames(){
System.out.println("play computer games....");
}
}
//测试类
class TestStudent{
public static void main(String[] args){
//方法一:通过set方法进行赋值
Student s1 = new Student();
s1.setName("迪丽热巴");
s1.setAge(28);
s1.setSex("女");
System.out.println("姓名:"+s1.getName()+",年龄:"+s1.getAge()+",性别:"+s1.getSex());
s1.study();
s1.playGames();
//方法二:通过有参构造进行初始化
Student s2 = new Student("古力娜扎",28,"女");
System.out.println("姓名:"+s2.getName()+",年龄:"+s2.getAge()+",性别:"+s2.getSex());
s2.study();
s2.playGames();
}
}
3.如何制作文档说明书
文档说明书的制作:
1)定义工具类 ArrayTool
2)无参构造方法私有化,外界不能创建该类对象,里面所有的功能全都是static的
3)在工具类中,对所有的功能加入文档注释
4)针对ArrayTool.java文件产生一个文档说明
打开dos--->进入到ArrayTool.java所在目录中
javadoc -d 目录名 -author -version ArrayTool.java
/**
这是一个针对数组操作的工具类
@author apple
@version V1.0
*/
//为了保证当前ArrayTool的访问权限足够大,加入public
public class ArrayTool{
//私有化:外界不能创建对象访问!
private ArrayTool(){
}
/**
这个方法针对数组的遍历操作,将数组元素一一输出[元素1, 元素2, 元素3, ...]
@param arr 需要遍历的数组
*/
public static void printArray(int[] arr){
System.out.print("[");
for(int x = 0 ; x < arr.length ; x ++){
if(x== arr.length-1){
System.out.println(arr[x] +"]") ;
}else{
System.out.print(arr[x]+", ") ;
}
}
}
/**
该方法是获取数组中的最大值
@param arr 在指定的数组中获取最大值
@return 返回的就是当前数组中的最大值
*/
public static int getMax(int[] arr){
//假设
int max = arr[0] ;
//遍历数组
for(int x =1 ; x < arr.length ; x ++){
if(arr[x] > max){
max = arr[x] ;
}
}
return max ;
}
/**
该方法获取数组中指定的元素出现的角标值
@param arr 在指定的数组中查询
@param key 表示指定的元素
@return 如果查找到了这个元素,直接返回角标值;如果找不到,返回-1
*/
public static int getIndex(int[] arr,int key){
//假设法
int index = -1 ;
//遍历数组
for(int x = 0 ; x < arr.length ; x ++){
if(arr[x] == key){
//改变index的值
index = x ;
break ;
}
}
return index ;
}
}
/**
该方法对数组进行冒泡排序
@param arr 在指定数组中进行排序
*/
public static void bubbleSort(int[] arr){
for(int x = 0;x<arr.length-1;x++){
for(int y = 0;y<arr.length-1-i;y++){
if(arr[y]>arr[y+1]){
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
4.代码块
Java中代码块:
使用{}包起来的内容,就称为代码块!
分类:
1)局部代码块
在局部位置中定义的{},作用:限定变量的声明周期
2)构造代码块
在类的成员位置中定义{},
特点:在当前类中,有限执行构造代码块,然后在执行构造方法...
(每次执行构造方法之前先执行构造代码块)
构造代码块的作用:对当前类的数据进行初始化!(很少用,笔试题!)
3)静态代码块
在{}的前面加上static
static{
....
}
静态代码块随着的类的加载而加载,由于类加载一次,静态代码块执行一次!
优先级:
静态代码块 > 构造代码块 >构造方法
二.继承
1.继承知识点
继承:将一些类共性的内容抽取出来,单独定义在一个类中,让这个独立的类和多个类产生一种关系,这种关系叫作继承关系(extends)
继承的好处:
1.提高了代码的复用性
2.提高了代码的维护性
3.类与类的产生的继承关系是多态的前提
继承的格式:
class 父类名{}
class 子类名 extends 父类名{}
继承的特点:
1.Java中类与类只能单继承,不支持多继承
2.Java中类与类可以多层继承
如:class A{}-----class B extend A{}----class C extends B{}
继承的注意事项:
1.子类继承父类,不能继承父类的私有的成员变量和私有的成员方法;
原因:被private修饰的成员外界访问不到,但是可以通过公共的方法来间接访问
2.子类继承父类,不能继承父类的构造方法,但是可以通过super关键字间接来访问
存在继承关系,类成员的访问问题:
1.子类和父类中的成员变量不一样的情况 :分别访问即可!
2.子类和父类中的成员变量一样: 遵循就近原则!
1).先在局部位置找,如果存在就使用
2).如果局部位置没有,那么就在子类中的成员位置找,如果有,则使用!
3).如果子类的成员位置没有,那么久在父类的成员位置找,如果有就使用!
4)如果父类的成员位置都没有,那么就访问报错,报错原因为不存在这个变量!
子类继承父类,关于构造方法的问题:
子类的所有构造方法默认访问父类的无参构造方法!
为什么要访问父类的无参构造方法?
构造方方法的目的:就是为了数据初始化
由于存在继承关系,创建的是子类对象,对子类初始化的时候执行构造方法,可能会用到父类的数据,所以必须先让父类初始化(会执行父类的构造方法),父类初始化完毕了才是子类初始化(分层初始化)!
*注意*:每一个子类的构造方法的第一句话是super() ;可以不写,super:代表的是父类的空间标识(大代表父类对象的引用地址)
注意事项:子类默认访问父类的无参构造,如果父类没有提供无参构造,会出现什么情况,怎么解决!
会出现编译报错,因为父类存在有参的无参构造方法,系统不会提供无参构造,又由于所有子类的构造方法都默认访问父类的无参,所以报错!
解决办法:
1.手动给出父类的无参构造方法
2.可以让子类所有的构造方法,默认访问父类的有参构造方法
在子类的的构造方法的第一句话加上super(xxxx);子类中所有的构造方法的一个只要能让父类初始化即可!
3.通过子类的有参构造方法,访问this()本类的无参构造方法,再通过本类的无参构造方法,访问父类的有参构造方法(让父类先进行初始化)
this和super的区别
this代表的当前对象的地址值引用
super代表父类对象的地址值引用
访问区别:
this.成员变量:访问的是当前类的的成员变量
super.成员变量:访问的是父类的成员变量
this.成员方法名():访问的是当前类的成员方法
super.成员方法名():访问的是父类的成员方法
this():访问的是本类的无参构造方法
super():访问的是父类的无参构造方法
this(xx):访问的本类的有参构造方法
super(xxx):访问的是父类的有参构造方法
继承关系中子类变量名和父类变量名一致的情况:先在子类的局部位置中找,然后在子类的成员位置中找,最后在父类的中的成员位置中找(成员方法名称与成员变量一致)
方法重载和方法重写的区别:
方法重载:方法名相同,参数列表不同(参数的个数和顺序),与返回值无关
方法重写:子类继承父类的时候,子类出现和父类一模一样的方法
final关键字的特点:
final:状态修饰符,最终的,无法更改的!
final修饰类,该类不能继承
final修饰变量,该变量此时一个常量!
final修饰成员方法,该方法不能被重写!
final修饰基本数据类型的变量和引用数据类型的区别:
final修饰基本数据类型则它的数值不能再改变了(具体的数值)
final 修饰的引用数据类型,它的地址值不能再改变了(成员变量的值不影响)
2.继承的应用
/*
猫狗案例
*
* 猫 事物
* 属性:姓名,年龄,颜色...
* 行为:猫吃鱼
* 抓老鼠..
* 吃 跑
* 狗 事物
* 属性:姓名,年龄,颜色...
* 行为:狗看门
* 吃 跑
*将猫和狗的共性内容,提前到独立类中----->动物类 Animal
*狗和猫继承自动物类
*/
public class Animal {
private String name;
private int age;
private String color;
//无参构造
public Animal() {
super();
}
//创建有参构造
public Animal(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
//get和set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//定义动物的方法
public void eat() {
System.out.println("eat...");
}
public void run() {
System.out.println("running...");
}
}
//狗类继承动物类
public class Dog extends Animal {
//无参构造
public Dog() {
super();
}
//有参构造
public Dog(String name, int age, String color) {
super(name, age, color);
}
public void seeDoor() {
System.out.println("see door.......");
}
public void eat(){
System.out.println("吃骨头....");
}
}
//猫类继承动物类
public class Cat extends Animal {
//无参构造
public Cat() {
super();
}
//有参构造
public Cat(String name, int age, String color) {
super(name, age, color);
}
public void catchMouse() {
System.out.println("我可以抓老鼠....");
}
public void eat() {
System.out.println("猫吃鱼....");
}
}
//测试类
class Test{
public static void main(String[] args){
//测试猫
Cat c = new Cat();
c.catchMouse();
c.run();
c.eat();
//测试狗
Dog d = new Dog();
d.eat();
d.run();
d.seeDoor();
}
}
三.多态
1.多态的知识点
多态:一个事物在不同时刻显示的不同状态(在堆内存中的变化)
多态的前提条件:
1).必须存在继承关系
2).要有要方法的重写(指的是非静态的方法)
3).要存在父类的引用指向子类的对象(向上转型)
格式:父类名 对象名 = new 子类名();
多态的成员访问特点:
1.成员变量:编译看左,执行看左
2.成员方法(非静态的):编译看左,运行看右(因为存在子类覆盖了父类的方法:方法的重写)
3.静态的成员方法:编译看左,执行看左
如果子类出现了与父类一模一样的静态方法,静态方法和类相关,不存在重写,访问方式是类名.方法名();
4.构造方法:由于存在继承关系,还需要分层初始化!
多态的好处:
1.提高的代码的扩展性
2.提高了代码的复用性,维护性
多态的弊端:
不能够访问子类的特有功能!
解决方式:
1.创建子类具体类对象: 子类名 对象名 = new 子类名();
对象自名.访问子类自己的功能;(比较消耗内存空间)
2.多态的第三条件:父类的引用指向子类的对象(向上转型)
父类名 对象名 = new 子类名();
再通过父类的引用强制转化为子类的引用(向下转型)
子类名 对象名 = (子类名)父类对象名;(不需要重新new对象,在堆内存中是比较节省内存空间的)
注意:使用向下转型必须先使用向上转型,否则会出现ClassCastException错误!
2.多态的应用
/*
* 猫狗案例,多态版进行测试
*
* 猫和狗:
* 属性:姓名,年龄,颜色
* 行为:吃/和睡的功能
* 共性内容---->动物类:Animal
* 属性:姓名,年龄,颜色
* 行为:吃/和睡的功能
* 提供:对外的公共访问方法以及无参/有参构造方法
* 猫类继承自动物类
* 提供无参/有参
* 覆盖吃和睡的功能
* 特有功能:
* 猫抓老鼠
* 狗类继承自动物类
* 提供无参/有参
* 覆盖吃和睡的功能
* 特有功能
* 狗抓兔子
*/
public class Animal {
private String name ;
private int age ;
private String color ;
public Animal() {
super();
}
public Animal(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
//alt+shift+s--r
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat() {
System.out.println("吃饭...");
}
public void sleep() {
System.out.println("睡觉...");
}
}
//猫类
public class Cat extends Animal {
public Cat() {
super();
}
public Cat(String name, int age, String color) {
super(name, age, color);
}
public void eat() {
System.out.println("猫吃鱼...");
}
public void sleep() {
System.out.println("猫趴着睡觉...");
}
//特有功能
public void catchMouse() {
System.out.println("猫抓老鼠...");
}
}
//狗类
public class Dog extends Animal {
public Dog() {
super();
}
public Dog(String name, int age, String color) {
super(name, age, color);
}
public void eat() {
System.out.println("狗吃狗粮...");
}
public void sleep() {
System.out.println("猫侧着睡觉...");
}
//特有功能
public void catchRabit() {
System.out.println("狗抓兔子...");
}
}
//测试类
public class Test {
public static void main(String[] args) {
//多态方式测试
//测试猫
//方式1:无参构造+setXXX(XX xx)
Animal a = new Cat() ; //向上转型
a.setName("tom");
a.setAge(4);
a.setColor("白色");
System.out.println(a.getName()+"---"+a.getAge()+"---"+a.getColor());
a.eat();
a.sleep();
//特有功能
// a.catchMouse() ;
//向下转型:
Cat c = (Cat)a;
c.catchMouse();
System.out.println("------------------------------------------");
//方式2:有参构造方法赋值
Animal a2 = new Cat("加菲猫", 3, "黄色") ;
System.out.println(a2.getName()+"---"+a2.getAge()+"---"+a2.getColor());
a2.eat();
a2.sleep() ;
//向下转型
Cat c2 = (Cat)a2;
c2.catchMouse();
}
}