java面向对象编程
1、对象和面向对象的概念
- 万物皆对象
- 面向对象指以属性和行为的观点去分析现实生活中的事物
- 面向对象指先以面向对象的思想去分析,然后使用面向对象的编程语言进行表达的过程
- C语言面向过程,C++面向对象和过程,java面向对象
- 面向对象三大特征(封装,继承,多态)
2、类和对象的概念
- 对象是现实生活中存在的实体,在java里边表示内存空间的一个存储区域(堆区)
- 类是一个抽象概念,会把相同特征和行为的抽象描述集合在一块。在java中体现为一个引用数据类型,里面包含描述特征/属性的成员变量和描述行为的成员方法
- 类是构建对象的模板,对象的数据结构由定义它的类来决定
2.1、类的定义
class 类名 {
类体;
}
2.2、对象的创建
new 类名(); 匿名对象:new person(),这里指没有引用
a.用new来创建对象的过程,叫做类的实例化
b.创建对象的本质就是在堆区申请一块存储区域,用来存放对象特有的信息
栈区,堆区,方法区三者之间的关系:
3、成员方法的定义
- 成员方法体主要用于编写描述该方法功能的语句块
- 成员方法可以实现代码的重用,简化代码
成员变量和成员方法都属于类内部的成员,因此可以直接访问成员变量不需要再加引用.的前缀
class 类名 {
返回值类型 成员方法名(形参列表){
成员方法体;
}
}
3.1、可变长参数的使用
一个方法的形参列表中最多只能声明一个可变长参数,并且需要放到参数列表的末尾
//自定义可变长参数的使用
void show(String... args){
for(int i=0;i<args.length;i++){
System.out.print(args[i])
}
}
4、方法的传参过程
int max(int i,int b){…}
int a=5;int b=6;int res = m.max(a,b)
- 为main方法中的变量a,b,res分配空间并初始化
- 调用max方法,为max方法的形参变量ia,ib分配空间
- 将实参变量的数值赋值到形参变量的内存空间去
- max方法执行完毕,释放对应的形参变量内存空间
- main方法res得到max方法的返回值
- main方法结束后释放相关变量的内存空间
4.1、参数传递的注意事项
/*
编程实现基本参数传递的测试
*/
public class ArgumentTest(){
void show1(int ia){
System.out.print("show1方法中:ia="+ia); //10
}
void show2(int[] arr){
arr[0] = 200;
System.out.print("show2方法中:arr[0]="+arr[0]); //200
}
public static void main(String[] args){
ArgumentTest a = new ArgumentTest();
int ib = 10;
a.show1(ib);
System.out.print("main方法中:ib="+ib); //10
int arr2[] = new int[]{10,20};
a.show2(arr2[0]);
System.out.print("main方法中:arr2[0]="+arr2[0]); //200
}
}
参数传递的注意事项:
基本数据类型的变量作为方法的参数传递,形参变量的改变不会影响到实参变量的数值,因为两个变量有各自独立的内存空间
引用数据类型的变量作为方法的参数传递,形参变量的改变会影响到实参变量的数值,因为这两个变量共用一个同一块内存空间
引用数据类型的变量作为方法的参数传递时,形参变量改变指定方向后在改变数值,不会影响到实参变量的改变,因为这两个变量指向不同的内存空间。
5、内存结构之栈区
- 栈用于存放程序运行过程当中所有的局部变量。一个运行的java程序从开始到结束会有多次方法调用
- JVM会为每一个方法的调用在栈中分配一个空间,这个空间称为栈帧。一个栈帧对应一个正在调用的方法,栈帧中存储了该方法的参数、局部变量等数据
- 当某一个方法调用完成后,会释放该栈帧
6、构造方法的概念和使用
6.1、构造方法的基本概念
构造方法名与类名完全相同并且没有返回值类型,连void都不许有
class 类名{
类名(形参列表){
构造方法体
}
}
/*
编程实现Person类的定义
*/
public class Person{
String name;
int age; //用于描述年龄的成员变量
//无参构造
Person(){
}
//自定义构造方法
Person(String name,int age){
this.name = name;
this.age = age;
}
//自定义成员方法实现所有特征的打印
void show(){
System.out.println("我是"+name+",今年"+age+"岁了")
}
public static void main(String[] args){
//声明一个Person类型的引用指向Person类型的对象,调用默认构造方法
Person p1 = new Person();
//打印特征
p1.show(); //null 0
Person p2 = new Person("张飞",30);
p2.show(); //张飞 30
}
7、重载的体现形式
- 方法重载的主要形式体现在:参数的个数不同、参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
8、this关键字的基本概念
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
- this关键字本质上就是当前类类型的引用变量。
- this遵循就近原则
/*
编程实现this关键字的使用
*/
public class ThisTest{
//自定义构造方法
ThisTest(){
//this代表当前正在构造的对象
System.out.print("构造方法中:this ="+this); //打印当前对象的地址值
}
void show(){
//this表示当前正在调用的对象
System.out.print("成员方法中:this = "+this); //打印当前对象的地址值
}
public static void main(String[] args){
ThisTest tt = new ThisTest();
System.out.print(" tt ="+tt); //打印当前对象的地址值
tt.show();
}
}
8.1、工作原理
- 在构造方法中和成员方法中访问成员变量时,编译器会加上this.前缀,而this.相当于汉语中”我的“,当不同的对象调用同一个方法时,由于调用方法的对象不同而导致this关键字不同,从而this.方式访问的结果也就随之不同
8.2、使用方式
- 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量。
- this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值。
- 在构造方法的第一行可以使用this()的方式来调用本类中的其他构造方法。
9、static关键字的基本概念
- 使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级提升为类层级,也就是整个类只有一份并被所有对象共享,该成员变量随着类的加载准备就绪,与是否创建对象无关。
- static关键字修饰的成员可以使用引用.的方式访问,但推荐类名.的方式。
//隶属于对象层级,也就是每个对象都拥有独立的一份
private String county
//隶属于类层级,也就是整个类只有一份并且被所有对象共享
private static String county
9.1、static使用方式
- 在非静态成员方法中既能访问非静态的成员又能访问静态的成员。(成员:成员变量+成员方法,静态成员被所有对象共享)
- 在静态成员方法中只能访问静态成员不能访问非静态成员。(成员:成员变量+成员方法,因为此时可能还没有创建对象)
- 在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用static关键字修饰。(不能滥用static关键字)
10、构造块和静态代码块(熟悉)
- 构造块:在类体中直接{}括起来的代码块
- 每创建一个对象都会执行一次构造体
- 静态代码块:使用static关键字修饰的构造块
/*
编程实现构造块和静态代码块的使用
*/
public class BlockTest{
//当需要在执行构造方法体之前做一些准备工作时,则将准备工作的相关代码写在构造块中即可,比如:对成员变量进行统一的初始化操作
{
System.out.print("构造块!");
}
//静态代码块会随着类的加载而准备就绪,会先于构造块执行
//当需要执行代码块之前随着类的加载做一些准备工作,则编写代码到静态代码块中,比如加载数据库的驱动包等
static{
System.out.print("静态代码块!");
}
//自定义构造方法
public BlockTest(){
System.out.print("构造方法体!");
}
public static void main(String[] args){
BlockTest bt = new BlockTest();
}
11、单例设计模式的概念
- 在某些场合中,一个类对外提供且只提供一个对象时,这样的类叫做单例类,而设计单例的流程和思想叫做单例设计模式。
11.1、单例模式的实现流程
- 私有化构造方法,使用private关键字修饰
- 声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰
- 提供公共的get方法负责将对象返回出去,并使用public static关键字共同修饰
11.2、单例模式的实现方式
- 单例模式的实现方式有两种:饿汉式和懒汉式,在以后的开发中推荐饿汉式。
/*
编程实现Sinleton类的封装
*/
public class Singleton(){
//private static Singleton sin = new Singleton(); //饿汉式
private static Singleton sin = null; //懒汉式
//私有化构造方法
private Singleton(){}
//提供公共的get方法负责将对象返回出去
public static Singleton getInstance(){
//return sin;
if(null == sin){ //涉及到多线程抢占资源的问题
sin = new Singleton();
}
return sin;
}
}
12、继承的由来和概念
概念:
- 当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成一个公共类,让多个类吸收公共类中已有特征和行为而在多个类型只需要编写自己独有特征和行为的机制,叫做继承。
- 使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件。
12.1、继承的特点
- 子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承,只是不能被访问。
- 无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代码super()的效果。
- 使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。
- java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类可以有多个子类。
13、方法重写的概念和使用
概念:
- 从父类中继承下来的方法不满足子类的需求时,就需要在子类中重新写一个和父类一样的方法来覆盖从父类中继承下来的版本,该方式就叫做方法的重写。
13.1、方法重写的原则
- 要求方法名相同、参数列表相同以及返回值类型相同,从java5开始允许返回子类类型。
- 要求方法的访问权限不能变小,可以相同或者变大。
- 要求方法不能抛出更大的异常(异常机制)。
14、又见构造块与静态代码块
- 先执行父类的静态代码块,再执行子类的静态代码块
- 执行父类的构造块,在执行父类的构造方法体
- 执行子类的构造块,在执行子类的构造方法体
15、常用的访问控制符
16、final的使用方式
- final修饰的类不能被继承
- final修饰的成员方法可以被继承,不能被重写
- final修饰的成员变量必须要初始化,且不能被改变
17、多态的概念和语法
多态的语法格式
父类类型 引用变量名 = new 子类类型();
17.1、多态的特点
- 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法
- 当父类类型的引用指向子类类型的对象时,父类类型的引用不能直接调用子类独有的方法
- 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类版本
- 对于父子类都有的静态方法,编译和运行都调用父类版本
多态的意义:屏蔽不同子类的差异性实现通用编程带来的不同效果
17.2、引用数据类型之间的转换
- 自动类型转换主要指小类型向大类型的转换,也就是子类向父类,叫做向上转型
- 强制类型转换主要指大类型向小类型的转换,也就是父类向子类,叫做向下转型
- 引用数据类型的转换必须发生在父子类之间
- 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
- 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型