java面向对象

理论基本描述

面向对象(oop):由抽象到具体事物的过程称为面向对象,变量描述特征,方法描述行为。

堆、栈、方法区:

Person per=new Person();

java文件编译之后会生成一个对应的class字节码文件,运行Java程序的时候JVM中的类加载器将主类的class字节码文件以及该类的入口函数main和静态成员加载到内存中的方法区,然后main方法进栈执行方法中的代码,当通过new去创建一个类Person的实例化对象的时候(Person per=new Person()),Person.class进入方法区,然后去堆内存new Person(),这个时候由JVM提供的默认无参构造函数Person()进栈为person对象里面的成员变量进行默认初始化值,默认初始化完成之后构造函数Person()弹栈,至此,person对象在堆里面创建完成。同时JVM会为person对象分配一个堆内存地址,如0x1111,然后会创建一个this关键字来指向堆内存地址。等号左边Person per是在栈里面创建person对象的引用per,将堆地址0x1111保存到per引用对象里面,per指向的就是这个person对象的堆地址。per=this=0x1111,至此,person对象的初始化工作完成,然后使用引用对象per给对象里面的属性重新分配值(即手动赋值-------显示初始化值),下一步使用引用对象per来调用对象里面的属性和行为方法,最后直至程序执行结束main方法弹栈,JVM开始进行垃圾回收。

理论总结:

构造函数是用来构造对象的,名称跟类名一样,无返回值,可以有多个,方便在创建对象的时候可以传不同的参数列表(方法重载),为成员属性赋值。无参构造函数必须存在。执行程序的时候,class类和静态成员是加载到方法区,new的对象以及对象的成员属性是在堆里面创建,函数方法是在栈里面执行完后弹栈。在函数方法中使用变量有一个就近原则(局部变量优先于其他变量),this和普通成员随着对象的创建而创建,是属于对象级别的,static静态成员随着类的加载而加载,是属于类级别的,this的使用要滞后于static,因此,静态方法里面不能调用this且只能访问静态成员,非静态方法都可以访问调用。静态成员是共享的;对象调用成员变量是先在对象里面找(找到返回对象里面的值),找不到则去类里面找(类中找到则返回类中的值,因此可以通过类名.静态成员去访问,无需import导包,一般通过对象去调用需要导包),最后找不到就返回类型默认值。

封装

封装:基于安全性的考虑,我们需要将类中的成员变量私有化起来,然后对外提供接口。

步骤

1、通过private修饰来进行成员变量的私有化。
2、为每一个私有化起来的成员变量提供公共的对外的取值(getxxx)接口和赋值(setxxx)接口。
3、通过实例化出来的对象调用取值、赋值接口为对象的属性进行取值或赋值。
在这里插入图片描述

优点:赋值的时候通过set接口可以对用户输入的数据进行过滤(通过正则表达式判断是否非法),防止数据被攻击从而保证后台数据的安全性。通过get接口取值的时候,对从数据库拿到的数据进行过滤,防止数据被泄露从而保证后台数据的安全性,同时可以让用户看到便于理解的信息(如图片的话一般是存放图片的路径,需要逻辑代码的处理将其通过资源路径展示出来)。

代码块

由 {}括起来的称为代码块,代码块都是在栈里面执行完弹栈,可以分类为:
1、局部代码块:一般存在于普通方法里面,可以及时释放资源,限定某个变量和程序的生命周期。
2、构造方法代码块:创建对象的时候用来显示初始化值。
3、静态代码块:static{
逻辑代码
} //和类的加载时机一样,属于共享的,如一些驱动加载的代码可以放到静态代码块中,后面再创建对象的时候无需重复加载创建,以此来节省资源空间,如jdbc数据库驱动。
4、构造代码块:没有任何修饰符的代码块。{ } //在公共代码里面用。

代码块执行先后顺序:

在创建对象之前按照顺序执行静态代码块,然后执行构造代码块,创建对象时执行构造方法代码块,局部代码块是在调用的时候执行。静态代码块只在创建第一个对象时调用,它只执行一次,用来共享提高效率和资源利用率(如Spring容器加载、JDBC数据库驱动)。构造代码块在每个对象创建的时候都调用(项目中一般很少用)。

继承

继承:一个类(子类)沿用另一个类(父类)的成员属性和方法。
优点:提高了代码的复用性和维护性。
缺点:类的耦合性增强了。
开发原则是高内聚(模块化完成功能)、低耦合(类与类之间的关系要低)。继承将类的关系升高了,需要解耦。

继承注意事项:

1、Java中的类不支持多继承,但是可以支持多层继承,不建议为了部分功能去继承。
2、Object类是Java中所有类最顶层的父类,代码省略了 extends Object,JVM执行的时候会自动加上,因此,Object类中的公共方法是所有对象都可以使用的。如equals,hashcode等方法,具体可以去源码里面查找。
3、子类只能继承父类中的非私有成员(但是可以通过反射去暴力获取私有属性),因此父类中的成员最好定义成public。
4、除开构造方法,子类不能去继承父类的构造方法,但是可以通过super去访问父类的构造方法。
5、由final修饰的类是最终类,不能被继承。

super和this关键字:

super是父类的引用,this是子类当前对象的引用,在new子类的时候,根据extends关键字会生成对应父类的引用super,父类进入方法区,通过super调用父类的构造方法,成员属性。调用完成之后父类构造方法弹栈,子类构造方法进栈进行成员属性值显示初始化。
注意:在子类构造器中,super()和this()只能有一个,且必须写在子类构造器中的第一行。super只能调用父类成员,this既可以调用子类也可以调用父类中可继承的成员。子类中所有的构造方法都会调用父类中的无参构造方法super()。

继承中同名变量的关系

例子:父类
在这里插入图片描述

子类
在这里插入图片描述
当变量同名时,局部变量优先使用(num),子类变量用this.变量名调用(this.num),父类变量用super.变量名调用(super.num)。

重载和重写的区别

重载: 方法上面加注解@overload
一个类中多态的一种表现
重载原则:
1、重载方法名一样,返回值类型可以一样也可以不一样,参数列表不一样(参数类型、参数个数、参数顺序)。
同一个类的多个构造方法互为重载,重载方法是为了对象调用时可以传不同的参数,根据方法传递的参数来调用对应的方法。

重写: 方法上面加注解@override
重写原则:
需要有继承,子类想要重写父类中的方法需满足:
1、访问修饰符不能比父类中的小,最好保持一致。
2、方法名、参数列表和返回值要和父类一样。
3、重写方法一定不能抛出新的检查异常或者比被重写方法声明更加宽泛的检查型异常。
重写注意事项:
1、父类中的私有方法不能被重写,因为子类无法继承。
2、重写父类中的静态方法,子类必须通过静态方法进行重写。(即覆盖)
3、final修饰的方法是最终方法,不能被重写。
区别:
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或两者都不同)可以视为重载;重写发生在子类与父类之间,重写要求子类被重写的方法与父类被重写的方法有相同的参数列表,有兼容的返回类型,不能比父类被重写的方法声明更多的异常。

final关键字

由final修饰的成员存在堆里面的常量区,如String类型的字符串也是存在这里的。由final修饰的基本数据类型是值不能改变;由final修饰的引用数据类型是地址值不能被改变,但是对象中的属性可以改变;由final修饰的类是最终类不能被继承,如String;由final修饰的变量称为Java中的常量,只能赋值一次;由final修饰的方法是最终方法,不能被重写。

访问修饰符

public>protected>default>private
public所有类都可以访问。
protected除了不同包下的无关类不能访问外,其他都可以访问(不同包下的子类、同一个包下的无关类和子类都能访问)。
default是同一个包下面的无关类和子类都可以访问,不同包下的类都不能访问。不写修饰符默认就是default。
private只能在当前类访问。

多态

多态:一个事物在不同情况下的状态。多态便于扩展功能。
多态前提:
首先必须要有继承,必须要对父类的方法进行重写,必须要有父类动态引用指向子对象。
多态中的成员访问特点:
当父类动态引用指向子对象的时候:
对于普通成员变量来说,编译和运行都是父类中的成员变量生效。
对于普通成员方法来说,编译是父类的方法生效,执行是子类的方法生效。
对于静态方法来说,编译和运行都是父类中的成静态方法生效。

类型转换

原始基本数据类型有隐式转换和强制转换,低类型转高类型数据称为隐式转换,高类型转低类型数据需要强制转换,这种强制转换可能会导致数据精度丢失,如double转float会导致小数点后面几位丢失。
向下转型:当子类中的新增方法在父类中不存在时,父类引用子类方法需要强制将父类转换为子类类型,否则编译不通过。
向上转型:子类转父类去调用父类中的成员。
if(对象名 instanceof 类名) //判断对象是否是某一个类的实例,以此来进行转型。

抽象类

abstract class 类名{
public abstract void 方法名();

}
抽象类也是多态的一种,也是用来扩展功能的,按照多态的方式进行实例化,由具体的子类或者匿名内部类去实例化。抽象类和抽象方法必须用abstract关键字修饰,抽象类不一定有抽象方法,但是有抽象方法的类一定是抽象类或者接口。

抽象类继承

抽象类不能继承抽象类,普通类继承抽象类需要重写抽象方法,且重写的抽象方法要跟抽象类中的返回值类型,方法名一致。

abstract不能共存的关键字

1、static不能与abstract共存,因为static是在类加载的时候一起加载的,而abstract修饰的方法是需要通过对象重写,矛盾了。
2、private不能跟抽象类、方法共存,因为它被私有化了,不能被继承重写。
3、final不能跟抽象类、方法共存,因为final修饰的类是最终类,不能被继承,更不能被重写方法。但是抽象类里面可以使用普通变量和常量(final修饰的成员属性),abstract不能修饰成员属性,只能修饰类和方法,一个类里面只能有一个public类。

抽象类应用场景

将不确定的功能做成抽象的,让子类重写去实现具体的功能即可。例如:将不确定的动物种类做成一个动物抽象类,把动物共有的属性(姓名,年龄等)进行封装,分别提供对应的赋值、取值接口。再把动物吃的食物做成一个抽象方法。因为不同种类动物吃的食物不一样,要由具体的子类对象(具体的动物)来重写这个方法。

static关键字

static修饰的代码是静态共享的,和类一起加载存在于方法区中,static静态方法里面不能有静态变量,同时存在有冲突会报错,但是可以调用方法外的静态变量,即静态里面不能定义静态属性。static final 修饰的变量是放在常量池的,即final无论跟哪个关键字搭配都是放在常量池,且只有一次赋值机会。如果两个不同的静态变量的值相同,当第一个变量用final修饰为常量时,第二个值就不会存在在静态区了,它会引用第一个变量在常量池中的值。

dos下常用的Java命令

确保Java的安装环境、环境变量已配置好的情况下
进入到编译目录(有文件.class, .bak , .java),cmd到该路径,然后执行
javap -c java文件名 //反编译Java文件
javac Java文件名 //编译Java,生成字节码文件
java 文件名 //运行Java

接口

interface 接口名{…}
对外提供规则的都是接口,用interface修饰,接口需要具体的子类去实现接口中的抽象方法。实现接口用implements 。
class 类名 implements 接口名{…}

接口成员特点

接口不能直接实例化,要按照多态的方式来实例化。接口的子类需要重写接口中的所有抽象方法,接口中的变量都是静态的,并且是最终的(定义时不加static final,jvm默认加上),接口中的方法都是抽象方法(定义时不加abstract,jvm默认加上)。extends和implements可以同时使用,即子类可以同时继承和实现接口,用空格隔开,一个类可以实现多个接口,用逗号隔开。

类与接口之间的关系

1、类与类:可以多层继承。但只能单继承(接口解决了这个问题,可以多继承)。
2、类与接口:可以多实现也可以单实现,且可以在继承一个类的同时实现多个接口。
3、接口与接口:可以单继承也可以多继承。

抽象类与接口的区别

抽象类接口
有构造器没有构造器,因为成员方法都是抽象的,没有普通方法。
成员属性可以变量也可以常量成员属性只有常量,因为没有构造器,不能变量默认初始化。
成员方法可以抽象也可以非抽象成员方法只有抽象方法。

设计理念区别

抽象类被继承体现的是“is a”的关系,抽象类中定义的是该继承体系的共性功能(即复用功能);接口被实现体现的是“like a”的关系,接口中定义的是该继承体系的扩展功能。如USB线既可以充电也可以传输文件,usb可以写到接口里面作为一个抽象方法,后面实现类分别写充电的功能、传输文件的功能。

内部类

内部类访问特点

一个类A里面嵌套一个类B,B就是内部类。代码源文件编译后上方会有一个美元符号$来标识内部类。

class  Outer{
...
class  Inner{......}
}

1、一般内部类可以直接访问外部类的所有成员,包括private私有的。但是静态内部类只能访问外部类的静态成员。

2、外部类要访问内部类的成员,需要创建对象。
外部类名.内部类名 对象名=外部对象.内部对象

3、内部类里面的成员属性默认用final修饰,即常量,内部类中不能定义静态成员。

局部内部类

在类中的方法里面定义的内部类

 class  Outer{
..
public void method(){
class  Inner{......}
}
}

1、方法中的内部类没有访问修饰符,只能访问方法中的局部变量,且局部变量是用final修饰的常量。因为内部类的生命周期可能会超过局部变量的生命周期,所以用常量,当为这个常量重新赋值时会报错。
2、外部类看不见方法中的局部内部类,但是局部内部类可以访问外部类的任何成员。

匿名内部类

内部类的简化写法,前提是存在一个类或者接口(这个类可以是具体的类也可以是抽象类)。
new 类名(){
重写方法;
}; //加分号是因为前面new是一个创建对象的语句。其本质是一个继承了该类或者实现了该接口的子类匿名对象。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值