面向对象是一种从宏观上对问题进行分析的思想,即设计者思维。
关注的焦点是类:在计算机程序设计过程中,参照现实中事物,将事物的属性特 征、行为特征抽象出来,用类来表示。
典型的语言:Java、C#、C++、Python、Ruby和PHP等
代码结构:以类为组织单位。每种事物都具备自己的属性和行为/功能。
是一种设计者思维,适合解决复杂问题。代码扩展性强、可维护性高。
面向对象思想在实际应用中,从宏观上分析有哪些功能,再将功能进行分类,将不同的功能分到不同的类中,在具体实现中,仍然要使用面向过程。
一、类
概念:具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。
类的五大成员:
变量:一类事物属性的描述
方法:可以进行一定功能的实现的程序
构造器:可以对新建对象进行部分属性的初始化
代码块:
内部类:在类中声明的类,内部类也是外部类的成员。
1.内部类中可以直接访问外部类成员。
内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部 类可以自由地访问外部类的成员变量,无论是否为 private 的。
2.内部类只服务于当前外部类,其他类不能调用
内部类仍然是一个独立的类,在编译之后内部类会被编译成独立 的.class文件,但是前面冠以外部类的类名和$符号。
3.匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。当我们想使用某个接口或者抽象类的方法,而且只用一次,我们就可以使用匿名内部类。
new 接口名称/抽象类名称() {
重写抽象方法;
}
此处我们希望调用WindowAdapter类中的addWindowListener方法,但是只是用一次,于是使用内部类,并重写其中的addWindowListener方法。
类的成员变量与局部变量
在类中的位置不同
成员变量:在类中定义。局部变量:在方法中定义或者方法的参数
权限修饰不同
成员变量:可以使用权限修饰符 局部变量:不可以使用权限修饰符
初始化不同
成员变量:创建对象后,由构造方法初始化 局部变量:没有默认初始化值,必须定义,赋值。类的成员变量如果未初始化,系统机会赋默认值,基本数据类型会根据不同情况被赋值为0或0.0以及true或false,引用类型会被赋值为null。
生命周期不同
成员变量:随着对象的创建而存在,随着对象的销毁而消失 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
在内存中的位置不同
成员变量:与对象一起在堆内存中 局部变量: 与方法一样在栈中。
构造器:对对象进行初始化作用
1.构造器的名字必须与其所在的类名一致;构造器没有返回类型(也没有void来修饰),更没有return返回值。
2.一个类可以有多个构造器。
3.如果没有写构造器,也会默认有一个无参构造器。
4.当我们在类中写了构造器,则会自动覆盖默认的无参构造器,此时想再调用无参构造器,则需要再自己写一个无参构造器。
代码块:
内部类:在类中声明的类
代码块
代码块分为实例代码块和静态代码块
实例代码块每次创建对象时都会执行一次,可多次创建对象来多次执行实例代码块。静态代码块在类加载时执行一次,此后不会再执行。
方法重载
一个类中可以有多个相同名字的方法,但是要求其形参不同。
具体有以下不同
1.参数数量不同
2.参数类型不同
3. 参数顺序不同
tips:java方法重载和返回值无关
在进行调用时,会根据不同的参数选择不同的方法
值传递
1.基本数据类型的值传递
基本数据类型在进行方法调用时,方法的形参以另外的变量来获得传来的实参的值,然后对传来的值进行修改。完成后,并不会对原来的实参结果有影响,因为原来的实参在此的作用是对方法中的单元内容进行赋值,原来的实参并没有直接参与运算。
2.引用数据类型的值传递
在方法调用时,因为引用数据类型是通过传地址来进行数据的传递,所以形参和实参都会指向同一地址。如果在方法调用期间,形参改变,则是将所指向的地址的数值改变了,因为实参形参指向同一地址,所以实参的值也会跟着改变。
二、对象
对象:是类的一个实例,是以类为模板在内存中创建的实际存在的实例。
对象的创建和使用
Car bm = new Car();
Car bm:使用Car类作为类型声明一个变量bm.
new Car():使用new 创建对象,然后调用Car类的构造方法初始化对象.
= :将右边创建的对象地址赋给左边的bm变量
This关键字
this关键字通常作用在构造器和方法中,其作用是表示当前正在访问的对象。
下图中,因为是对象“person”在调用构造器,this.name便是代表正在访问的对象“person”的name。
Static关键字
static被称为静态,可以用来修饰类的成员变量,成员方法,代码块,内部类。
静态成员不依赖于类的某一个实例,而是被类的所有实例共享,就是说 static 修饰的 方法或者变量不需要依赖于对象来进行访问,只要这个类被加载,静态成员 就会被加载创建。
static关键字修饰的变量不会在创建对象时跟其他变量一起和对象存储在堆中,而是在类加载的时候存储在方法区的类中。也就是说,即使没有创建对象,也可以通过类名来调用静态变量和方法。
静态的方法中不能使用非静态的成员变量,因为二者的加载顺序不同。如果静态方法加载早于非静态成员变量,如果其中包含非静态成员变量,则会因为在加载完成静态方法时,非静态变量未加载而报错,故而静态方法中只能使用静态变量。但是在非静态方法中可以使用静态变量,因为在非静态方法加载时,静态变量都已经加载完成,所以没有问题。
静态方法中不能使用this和super关键字,因为this关键字是表示当前访问的对象,而静态方法加载在对象之前,所以不能使用。
包
随着项目越写越大,便会存在重名类的问题,为解决这一问题,Java中引入包这一概念。
包的作用: 按照不同功能管理类 避免类重名 控制访问权限。
包(package)的命名规范: 在包名中,可以使用.号来区分包的级别;包名一般情况下是小写 第一级 指该项目的类型,如com,org,gov等, 第二级 指项目所开发或者运行的公司名称,如:oracle,sun,huawei等 第三级 指项目的名称,如:bcms,oa,erp,cms等 第四级 指项目模块的名称,如:bean,action,exception。
在访问不同包中的类时,必须先使用import将其导入,同一包中的类则无需导入,以及java.lang包作为特例也不需要导入。一个类中只能导入一个类名相同的包,如果想调用另一个包中类名相同的类,则须进行如下操作。已经导入demo2中的car,但是还想使用demo1中的car,则需要在定义时完整的写出dome1中ca的地址。
访问权限修饰符
访问权限修饰符可以修饰成员变量,类(仅限于public和默认),内部类。
Java语言有四个权限访问修饰符,权限从大到小依次为:
1)public :公共权限 修饰类、属性、方法。可以在任意类中访问
2)protected:受保护的权限 修饰属性、方法。可以在同包类访问,如果 不是同包类,必须是该类的子类才可以访问。
3)default:同包权限 修饰类、属性、方法。只能在同包的类访问
4)private:私有权限 修饰属性、方法。 只能在本类中访问
三、面向对象三大特征
封装
封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是 通过该类提供的方法来实现对隐藏信息的操作和访问 。
封装的好处:可以通过特定的方法访问
隐藏类的信息
方便修改实现
方便加入控制语句
如何封装?
1.将属性私有化
2.设置get和set函数向外界提供入口
继承
当多个类同时存在相同的属性和方法时,为了提高代码的复用性,我们可以将其公共变量和方法提出来放到一个新的类中,然后用extends关键字使其继承新类,则称新类为其父类。
继承的细节
1.子类会继承父类的方法和变量
2.子类不能直接访问父类中私有的(private)的成员变量和方法
3.一个子类只能直接继承一个父类,但是可以多层继承(B继承A,C继承B)
4.子类必须调用父类的构造器,完成父类的初始化
方法重写
倘若父类的方法不能满足子类的需求,那么可以在子类中将父类的方法进行重写。重写后,实例会优先调用子类重写过后的方法。
重写的细节
1.子类重写的方法访问权限修饰符不能小于父类。
2.父类的私有方法不能重写
重写和重载的区别
继承中的构造方法
1.子类继承父类时,不会继承父类的构造方法。只能通过“super(形参列表)” 的方式调用父类指定的构造方法。
2.规定super(形参列表),必须声明在构造器的首行。
3.如果在子类构造器没有调用super,则子类此构造器 默认调用super(),即调用父类中无参的构造器。
4.这么做是为了保证先对父类成员进行初始化。
super关键字
super表示父类空间的标识。子类对象在进行创建的时候,会将父类的信息一并加载到子类对象中,super就是用来访问父类信息的。
super可用于访问父类中定义的属性
super可用于调用父类中定义的成员方法
super可用于在子类构造器中调用父类的构造器
抽象类
当父类的一些方法不确定时,我们可以使用abstract关键字来修饰该方法,这便是抽象方法。抽象方法没有方法体,需要子类去实现。由此可见抽象类的价值在于设计,具体实现在子类。
部分细节:
1.abstract只能用来修饰类和方法,不能修饰属性和其他的。
2.抽象类中不一定要有抽象方法,但是类中一旦有了抽象方法,就必须定义成抽象类。
3.抽象类中既可以有抽象方法,也可以有非抽象方法。
4.抽象类不能被实例化(不可以用来创建对象)。
5.抽象方法没有方法体。
6.如果一个非抽象类继承了抽象类,那么必须实现抽象类中的所有抽象方法。
多态
多态即同一事物在不同时刻具有不同的形态。
编译期:写代码时
运行期:运行代码时
编译期只能调用父类的方法,在实际进行调用时,当子类重写了父类方法,则调用的是子类的方法。特殊情况,因为静态方法不能重写,所以当父类中有静态方法,子类中有重名的静态方法时,以对象名实际调用的还是父类中的静态方法。除非用子类名直接调用。
总结,非静态成员方法,编译看左边(编译类型),运行看右边(运行类型)。静态成员方法以及编成员变量编译和运行都看左边(编译类型)。
1.向上转型
当编译期类型是父类,运行期类型是子类时,被称为父类引用指向子类对象,即向上转型。
2.向下转型
子类中含有某些特有的方法时,向上转型的对象无法在编译时进行调用,此时需要向下转型,将对象的变异类型转化成子类类型。(向下转型只能强转父类的引用,不能强转父类的对象)
final关键字
final 用于修饰类,方法,参数,和属性
类:不能被定义为抽象类或是接口,不可被继承
方法:子类里不可以重写
属性:定义时就必须直接赋值或者在构造方法中进行赋值,并且后期都不能修改。
参数:参数值在方法中不可被修改
接口
接口中可定义属性,抽象方法,静态方法以及默认方法。
接口中的属性默认以public static final修饰。
接口中的抽象方法默认以public abstract修饰。
一个类可以实现多个接口,一个类实现一个接口时,必须实现里面的所有抽象方法。一个接口也可以继承多个接口。
类实现接口可以看作是类继承了另一个抽象类,在实现接口后,可以用多态的思想去创建实例。
JVM虚拟机内部
堆
堆是用于存储动态分配的内存空间,它是Java虚拟机(JVM)所管理的内存中最大的一块区域。
堆的主要作用是存放对象实例和数组。当我们使用new
关键字创建一个对象时,JVM会在堆中为其分配内存空间。
栈
栈主要用于存储局部变量、方法调用和返回值等,是线程私有的,内存分配和释放由编译器自动完成。