黑马程序员------面向对象

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

面向对象概述:
1、面向对象和面向过程都是一种思想
2、面向过程:强调执行过程,也就是功能
3、面向对象:将功能封装进对象,强调具备功能的对象

面向对象三大特征:
封装,继承,多态

类:
1、类就是对现实生活中事物的描述
2、对象就是这类事物中实际存在的个体
3、对象的创建就是在堆中开辟一处空间:
例子:
这里写图片描述
这里写图片描述
4、创建对象:有new关键字的时候才会新创建一个对象,赋值就只是把地址值传递过去;

show打印的信息:哪个对象调用这个方法,那他打印的就是那个对象的信息

举例:
一个类相当于一个设计图纸,而对象相当于实际个体,新建一个对象会根据图纸进行产生
改变对象的信息不会改变图纸的信息,当再重新产生一个对象的时候还是会根据图纸进行初始化

全局变量和局部变量:
范围:全局变量作用于整个类中,局部变量作用于 { }之内
内存位置:全局变量存在于堆中,局部变量存在于栈中

匿名对象:是对象的简化书写
例如:
Persion p = new Persion(); 对象有名称:p
new Persion();对象没有名称

匿名对象调用属性没有意义:
例:new Persion().age = 3;Sop.(new Persion().age);因为这里有new,所以重新产生了一个对象,打印的不是刚才对象的信息
匿名对象调用方法才有意义:new Persion().show();简化书写,当这个对象只是调用方法一次时候,可以使用匿名对象

传递匿名对象的时候栈中不需要创建变量,当方法运行完之后由于没有指向对象,这时候就变为垃圾,在不确定时间回收

封装:
隐藏方法的具体实现细节,仅对外提供公共访问方式(调用方法->传递参数->返回结果->不需要知道方法实现细节)
好处:
1、将变化隔离
2、便于使用
3、提高重用性
4、提高安全性
原则:将不要对外提供的内容都隐藏起来,把属性也隐藏起来,提供公共方法对其进行访问
属性被直接访问会造成安全隐患:
例如 :p.age = -10;无法对传入的参数进行逻辑判断
访问属性的时候使用set(),get()方法,可以对传入的值进行判断,提高安全性

构造函数:
特点:
1、函数名和类名相同
2、不用定义返回值类型
3、不可以写return 语句

作用:
给对象的值进行初始化
注意:多个构造函数是以重载的形式存在的

重载:
方法名相同,但是内部参数个数或者类型不同(跟修饰符没有关系,public,private,static等不影响)
例如:public static void a() {}:private void a() {}(这两个方法编译器会认为是同一个方法)

类默认会有一个空参数的构造函数,若是自定义了构造函数,就不会产生空构造函数,当对象建立的时候会自动调用与之对应的构造函数

构造函数和一般函数:
1、
构造函数是对象一建立就运行;
一般函数是对象调用才运行
2、
构造函数只运行一次
一般函数可以运行多次

构造代码块: { }
1、给 所有 对象进行初始化
2、对象一建立就运行,优先于构造函数运行
3、构造代码块是给所有的对象进行初始化,构造函数是给对应的对象进行初始化

this
哪个对象调用this,this就指向哪个对象
构造函数之间的调用只能使用this,并且this语句必须在第一行

    public Demo() {
    }
    public Demo(int a) {
        "//调用本类构造函数,不用加."
        this();
    }

    Persion p1 = new Persion(10, "ls");
    p1.show(new Persion(12, "123"));
    public void show(Persion p) {
        System.out.println(this.age - p.getAge());"//this-->p1,p-->new Persion(12, "123")"
        System.out.println(this.name.equals(p.getName()));
    }

static 静态
特点:
1、随着类的加载而加载,随着类的消失而消失
2、优先于对象存在
3、被所有对象所共享
4、可以直接用类名调用:Persion.show()
(不全部使用静待变量是因为有些数据不需要被共享,静态变量生命周期长,会大量消耗内存)

注意:
1、静态方法只能访问静态成员
2、静态方法中不能写this ,super(因为this 需要对象,而静态在对象之前就能调用)
3、主函数是静态的
4、静态变量存在于方法区中,类中的方法也存在于方法区中,类中的成员变量存在堆中,局部变量在栈中

什么时候使用静态
1、变量:当对象中出现共享数据时,使用静态(数据指的的他们值相同,而不是类型相同)
例如:张三李四都有名字,他们有相同属性,但是他们的值不同,这时候不能使用静态
共享数据 = 值相同
函数:当函数中没有调用非静态数据时候,就可以使用静态

静态方法之间的调用:使用类名.方法名 的方法

静态代码块:
为对象进行初始化
static {
执行语句
}
随着类的加载而加载,静态代码块>代码块>构造函数

主函数:
1、是一个特殊的函数,作为程序的入口,可以被jvm识别并调用
2、public static void main(String[] args) { }
public:访问权限最大
static:静态,随着类的加载而加载
void:没有返回值
main:不是关键字,但是能够被jvm识别
String[]:参数类型(参数类型必须是String[],若是其它参数类型则认为是重载,变量名称可以改变)
默认传递的值是new String[0]

对象额初始化过程:
Persion p = new Persion()
1、加载Persion.class类到内存中
2、执行静态代码块,给Persion类初始化
3、在堆中开辟内存空间
4、在堆中建立特有属性,并给默认值
5、对属性进行显示初始化
6、执行构造代码块
7、执行构造函数
8、将内存中的地址值给栈中的变量

单例设计模式:
解决一个类在内存中只能有一个对象的问题
方法:
1、禁止其他类创建对象:把构造函数私有化 private
2、本身建立一个对象
3、对外提供方法获取这个对象

饿汉式:

"//私有化构造函数,不能创建对象"
 private Perion() {
 }
"//本身建立一个对象,static:因为无法创建对象,所以方法要使用静态,静态不能访问非静态变量,所以设置为静态"
 private static Persion p = new Persion();
"//返回对象"
 public static Persion getP() {
  return p;
 }

懒汉式:

 private Perion() {
 }
"//一开始不创建对象,只是声明一个对象"
 private static Persion p = null;
"//先判断p是否为空,不为空就创建对象"
 public static Persion getP() {
  if (p == null) {
"//同步代码块,线程安全,不使用同步函数是因为使用同步函数每次都要获取锁,降低效率"
   synchronized (Persion.class) { 使用的锁是该类的字节码文件(唯一)
"//二次判断,提高效率"
    if (p == null) {
     p = new Persion();
    }   }  } 
  return p;
 }

继承:
不断地向上抽取共性的过程:关键字:extends
作用:
1、提高了代码的复用性
2、让类与类之间产生了关系,有了这个关系就有了多态
(注意:不要为了获取其他类的功能或简化代码而去继承其他类,继承是两个类之间存在联系
判断方法:可以让类A继承 类B,看看类B中的所有方法类A都适合用,若是有不适合用的方法,那就不要继承)

Java支持单继承(接口支持多继承,但是接口内部同名方法的返回值必须相同),不支持多继承,一个类只能继承一个类
多继承容易存在安全隐患:当多个父类中定义了相同名称的函数,但是他们的内容不同,这时候子类调用的时候就不知道调用那个方法了

Java支持多层继承: a extends b ; c extends b;

class A extends B{}
class B extends c{}

继承体系在创建对象时的最好创建子类的对象,原因:
1、父类可能不支持创建对象
2、子类继承了父类的所有基本功能,同时也能够使用自己的特殊功能
(查阅父类功能,能了解整个体系的基本功能,创建子类对象,能使用所有的功能)

字父类的出现导致类的变化:
(用子类创建对象,加载子类时候会加载父类)

1、变量:
本类调用本类同名变量使用this关键字
子类调用父类同名变量使用super关键字

2、函数:
子类和父类拥有同名函数,这时候运行的是子类函数(父类的函数也会加载进内存,只是不调用)
原因:子类重写了这个方法(覆盖这个方法)
使用场景:子类继承了父类的功能,但是子类实现的内容和父类不相同,这时候没必要重新写函数
直接使用相同名称的函数名,重写内部内容即可,提高了程序的扩展性(若是更改名字会导致代码不方便阅读)
注意:子类覆盖父类的函数权限必须保证大于等于父类的权限,否则编译失败(public private protect)
静态函数只能覆盖静态函数

3、构造函数:
子类的构造函数默认第一行(构造函数必须是第一行)都会调用父类的空参构造函数(若是父类没有空参构造函数,则要手动指定)
原因:
因为子类继承了父类,那就获取了父类的数据,子类在建立的时候需要知道父类是如何初始化这些数据的,所以要访问父类
当子类的构造函数中有存在this时候,这时候子类调用了本类的其他构造函数,这时候这个构造函数中没有super语句,但是他调用的那个构造函数的第一行会有super语句(最少会有一个super语句调用父类构造函数)

final:
1、可以修饰类,方法,变量
2、修饰的类不可以被继承
3、修饰的方法不能被覆盖
4、修饰的变量只能赋值一次,变成常量
5、内部类只能访问被final修饰的变量

抽象类:
特点:
1、抽象方法必须存在于抽象类中
2、抽象类不能创建对象(因为抽象类只是定义了方法名称,没有具体实现细节,调用无意义)
3、抽象类和抽象方法都用abstract修饰
4、子类必须重写父类所有抽象方法才能创建对象,若是只实现一部分父类抽象方法,则子类也是抽象类,无法创建对象
5、抽象类既可以存在抽象方法也可以存在正常方法
6、强制子类实现父类方法,使该类无法创建对象(没有抽象方法,单纯的抽象类)
7、抽象类中不一定有抽象方法,有抽象方法一定是抽象类
例子:工人类,普通员工,经理,普通员工和经理都需要工作,但是他们工作的内容却不相同,这个时候工人类中定义了工作的抽象方法,普通工人和经理都必须重写这个方法(若只是继承不使用抽象类则普通工人或者经理不需要必须重写这个方法,可以直接调用父类的方法,但是父类的内容却不一定适用)
重载和重写的区别:重载是本类中方法名相同,但是他们的参数类型或者参数个数不同,重写是子类有方法名和父类的方法名相同,子类方法重新定义了方法内容

模板方法设计模式:
在定义功能时候,功能一部分是固定的,但是有一部分是不确定的,这时候把不确定的那部分暴露出去,让子类完成不确定的部分
例子:

abstract class Fu
{
   public void getTime(){
  int start = System.currentTimeMillis();
  method() ;"//执行代码部分,不确定部分"
  int end = System.currentTimeMillis();
  System.out.println(start-end);
 }
 abstract void method(); "//对外提供方法暴露出去"
}

class Zi
{
 void method(){ "//子类实现这部分代码"
 执行代码;
 }
}

当子类实现完成后,创建对象,调用getTime()方法就可以获取代码运行时间

接口:interface
特点:
1、接口是对外暴露的规则
2、接口是程序的扩展
3、接口可以用来多实现(实现多个功能)
4、类与接口是实现关系,而类可以继承类同时实现接口
5、接口可以继承接口(继承后父类的方法子类也继承过来了,接口之间可以多继承,但是同名方法必须返回值相同,否则报错)
6、降低代码之间的耦合性
7、无法创建对象
8、内部方法全部是抽象方法
9、成员常量:public static final(固定格式,public static final可以不写,jvm会自动帮你补上)
成员函数:public abstract (固定格式,public abstract jvm会自动补上)

继承和接口的区别 :
实际例子:公务员,张三是公务员,公务员的所有福利张三都有(继承),但是张三自己开了一个小店,这个小店是张三另外拥有的福利(接口)
基本的功能都存在于类中,存在于体系之中,继承时所有的基本功能都能获取
扩展功能存在于接口中,不一定其他子类拥有,实现这个接口才拥有这个功能

多态:
某一种事物的多种存在形态
例如:动物 :猫、狗
动物 x = new mao();
类型 实体类
(重载和重写也是多态的体现)
a instanceof Cat (a 是不是属于Cat类型的对象)

多态的体现:父类的引用指向子类的对象
多态的前提:
1、类与类之间必须有关系,要么继承,要么实现。
2、存在覆盖。父类中有方法被子类重写。
多态的好处:提高代码的扩展性
多态的弊端:使用多态后不能访问子类的特有方法,只能访问父类的方法,但是执行时执行的的是子类的方法
若要使用子类特有的方法就必须向下转型:
Animal a = new Cat(); Cat c = (Cat)a;
Animal a = new Animal();此时父类自己创建对象,这时候不能向下转型,报错:类型转换异常

多态的特点
1、多态中非静态成员函数的特点
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。这就是说,如果父类中有一个非抽象的方法,而子类继承后又将其复写了,在多态运行时,父类的引用调用这个同名函数时,被运行的将是子类中的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

2、多态中成员变量的特点
如:多态中的父类引用调用成员变量时,如果父类和子类有同名的成员变量,那么被调用的是父类中的成员变量。

3、多态中静态成员函数和变量的特点
无论编译和运行,都参考左边。也就是父类引用在调用静态同名函数时,被调用的是父类中的静态函数。这是因为,当类一被加载,静态函数就随类绑定在了内存中。此时,不需要创建对象,就可以使用类名直接调用。同时,父类中的静态成员函数一般是不被复写的。

内部类
描述一个事物时候,这个事物之中还有事物,此时内部的事物就用内部类来表示
1、内部类可以直接访问外部类的成员,包括私有成员(内部类持有一个外部类的引用:外部类名.this. )
2、外部类访问内部类必须创建对象(当内部类定义在外部类成员位置上,而且是非私有时,可以在外部其他类中进行调用)
(外部其他类创建方式:外部类名.内部类名 变量名 = new 外部类名()new 内部类名() :Hman.Inner inner = new Hman().new Inner();)
3、当内部类在成员位置上就可以修饰符修饰,包括static
当内部类被静态修饰,内部类就具备了静态的特性:
(1)、只能访问外部静态函数和变量
(2)、当内部类中有静态方法时候,内部类必须是静态,内部类是静态,内部类中所有方法不一定都是静态
(3)、外部其他类访问静态内部类非静态函数创建对象:
外部类名.内部类名 变量名 = new 外部类名.内部类名(); :Hman.Inner2 hi = new Hman.Inner2();
(4)、外部其他类访问静态内部类静态函数创建对象:
外部类名.内部类名.函数名 Hman.Inner2.show();
4、外部类静态方法访问内部类时,内部类必须是静态

局部内部类:
1、定义在方法中(创建对象和调用时候不能出这个方法,因为一旦方法结束就会被销毁,此时局部内部类就不存在了)
2、可以访问外部成员(包括私有和静态,外部类名.this. 外部类名. )
3、不能使用修饰符修饰(因为方法内部不能使用修饰符修饰,所以也不能成为静态)
4、可以访问局部变量,但是局部变量必须使用final修饰,由于函数在执行完之后会被销毁,所以变量在被每一次調用時候都是重新赋值,并不和final冲突, 但是在函数中不能对变量的值进行修改,因为变量的值已经是final,不能更改变量的值
5、调用方法时候要在内部类所在的函数中创建对象
6、不能够被外部其他类直接调用,外部其他类可以调用这个外部类方法(内部类所在的方法)来执行

匿名内部类:
1、就是内部类的简写格式
2、内部类必须继承一个类或实现一个接口
3、匿名内部类不能调用外部类的成员(成员变量和成员函数)
4、实现方式:new 父类或接口(){
实现父类或接口的方法,也可以自定义方法
}.show();//这里进行执行相应的方法,既可以使用子类特有的方法,也可以使用父类的方法
5、内部类中也可以直接创建变量,打印的时候也是局部的数值
6、匿名内部类就是一个匿名子类对象,而且是带内容的子类对象
7、匿名内部类不能定义在成员上

实例:
1、先定义一个类或接口

class inner{
}
class A{
    show(){
        new Inner(){

        }
    }
}

1、class inner{ }//首先定义一个类或接口
2、new inner(){ }//若是没有大括号就是创建了一个inner的对象,若是有大括号就是创建了一个inner的匿名子类,大括号内可以写方法以及变量(子类的方法和变量),在大括号值后可以直接调用(方法和变量)
inner i = new inner(){ }//变为了多态,i不能调用大括号内的特有方法和变量,只能调用inner中有的方法和变量(匿名子类向上提升)

异常:是问题的描述,将问题进行对象的封装
异常体系:
Throwable
|–Error
|–Exception
|–RuntimeException
特点:
1、异常体系的所有类以及建立对象都具备可抛性,可以被throw和throws关键字操作,只有异常体系具备这个特点

throw和throws区别:
1、throw定义在函数内,用于抛出异常对象
2、throws定义在函数上,用处抛出异常类,可以抛出多个异常,用逗号隔开
当函数内容有throw抛出异常对象,并未进行try处理,必须要在函数上声明,否则编译失败
(Runtime异常除外,如果抛出的是Runtime异常或他的子类,函数上不用声明,可以通过编译)

当函数声明了异常,调用者在调用这个函数的时候要么try处理,要么抛出

异常两种:
编译时异常:编译时如果没有处理,(throws或try)编译失败
运行时异常:编译时不进行检测,发生这个异常可以不用声明,建议不处理,直接停止程序,让调用者修改数据

异常处理语句:
try{被检测的代码}
catch(Exception e){处理异常的代码}
finally{一定执行的代码(通常是关闭资源),若是前面语句中有Syste.mexit(0),finally就不会执行,因为前面的意思是退出虚拟机}

自定义异常:
继承RuntimeException或Exception
1、为了让该类具备可抛性
2、让该类具备操作异常的共性方法
3、当要自定义异常信息时,可以使用父类已经定义好的功能,异常信息传递给父类构造函数

class A extends Exception
{
    a(String msg){
        super(msg);
    }
}

异常的好处:
1、将问题进行封装
2、将正常流程代码和问题处理代码分离,方便阅读

异常处理原则:
1、try或者throws
2、调用异常抛出功能时候,抛出几个异常就处理几个异常,不要多处理,也不要少处理
3、多个catch时候,父类异常的catch放在最下边
4、catch内定义针对性的处理方式,不要只是简单的输出,更不要什么都不写
5、当捕获到异常的时候,本功能处理不了,可以在catch中继续抛出
try{
throw new AExeption();
}catch(AException e ){
throw e;
}

6、异常可以处理,但是要让调用者知道出现异常并处理(例如数据库,因为出现异常,然后自己已经处理完毕,但是数据并没有存入数据库,此时抛出异常,告诉调用者数据并没有存入数据库,让调用者自行处理)
try{
throw new AExeption();
}catch(AException e ){
throw new BException();
}
异常注意事项:
在子类覆盖时
1、子类抛出的异常必须是父类异常的子类或者子集
2、如果父类或者接口没有异常抛出,子类覆盖方法时候只能try不能抛
3、当try中只有一句throw new 。。。的时候,下面不要写语句,因为执行不到,此时 类似于return语句

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值