目录
一、面向对象概述
-
面向对象是一种编程思想,参考现实中的事物,在程序中把所有的事物通过属性和功能进行描述。
-
面向对象与面向过程的比较:
-
面向过程:
关注点是步骤,如何做,程序员是执行者。
-
面向对象:
关注点是谁能做,由谁做。程序员是指挥者。
-
二、类与对象
-
Java类:一类具体共同特征的事物的抽象描述,比如学生,汽车,手机;
-
Java对象:一个具体的事物,比如:张三是一个学生对象,我的手机是一个具体的手机实体。
-
类与对象的关系:
-
类是对象的模板,通过类可以创建对象。
-
对象是类的具体实例。通过类创建对象的过程称为实例化。
-
-
类的定义格式:
修饰符 class 类名{ //类的成员: //属性-变量 //功能-方法 } //定义一个学生类 public class Student{ //属性-变量 String name; int age; //功能-方法 public void study(){ System.out.println("学习...."); } }
-
对象的创建
类名 对象名 = new 类名(); //创建一个学生对象 Student stu = new Student(); //使用对象 stu.name = "tom"; stu.age = 18; stu.study();
三、包
包在磁盘中表现为文件夹。
-
包的作用:
-
避免类名的重复,这是类的全称是:包名+类名,比如:com.atguigu.Demo
-
方便分类管理众多的类,比如java.lang包下是最核心的类
-
配合权限修饰符实现访问权限管理
-
-
包的声明:
定义类时必须声明类所在的包,使用关键字package,并且声明语句必须在当前文件的第一行。
包名要符合标识符命名规范:即全小写字母组成,使用点.分隔开。
package com.atguigu.test05method;
-
跨包使用类的问题
在一个类中使用其他包下的类,需要导包,使用关键字import导包,写在当类声明之前,包声明之后。
import java.util.Arrays;
注意:java.lang包下的类可以直接使用,无需导包。
四、成员变量
Java类使用成员变量描述类的属性信息。
-
变量分类
-
成员变量:声明在类的直接成员位置,与方法并列
-
类变量-静态变量:有static修饰(后面讲)
-
实例变量-非静态变量:没有static修饰
-
-
局部变量:声明在方法中或参数上等局部区域。
public class Student{ //成员变量 static String school;//类变量-静态变量 String name;//实例变量-非静态变量 //方法 void test(int x){//变量x是局部变量 int a = 10;//变量a是局部变量 } }
-
-
实例变量的特点:
-
实例变量必须通过对象来访问,访问方式:对象.实例变量
-
实例变量值是每个对象独有一份
-
实例变量有默认初始值,类同数组元素的默认初始值。
Student stu = new Student(); System.out.println(stu.name);//null 默认初始值 stu.name = "tom";// System.out.println(stu.name);//tom Student stu2 = new Student(); System.out.println(stu2.name);//null 默认初始值 stu2.name = "张三";// System.out.println(stu2.name);//张三
-
-
实例变量的内存分析
-
实例变量与局部变量的区别
实例变量 局部变量 声明的位置 直接声明在类的成员位置 声明在方法体中或其他局部区域内(方法声明上,构造方法,代码块等) 修饰符 public、private、final等 不能使用访问权限修饰符,可以使用final 内存加载位置 堆 栈 初始化值 有默认初始化值 无默认初始化值 生命周期 同对象的生命周期 随着方法的调用而存在,方法调用完毕即消失
五、方法
1、概念理解
-
方法是一个特定功能的代码块,把功能封装到方法中主要目的是重复利用代码。
-
Java类使用方法来描述类的功能。
2、方法的分类
-
静态方法-类方法:有static修饰(后面讲),可以通过类名直接调用
-
非静态方法-实例方法:没有static修饰,必须通过对象调用。
3、方法的声明
-
方法声明的位置必须在类中方法外,在类的成员位置,所有方法声明必须是并列关系
-
声明格式:
【修饰符】 返回值类型 方法名(【参数列表 】)【throws 异常列表】{ 方法体; 【return 返回值;】 }
-
格式说明:
-
一个完整的方法 = 方法头 + 方法体。
-
大括号内为方法体,主要来实现功能;
-
大括号之前的内容是方法头,也称为方法签名。通常调用方法时只关注方法头即可。方法头包含5部分,有些部分可以缺省。
-
-
修饰符: 修饰符后面详细讲,例如:public,static等都是修饰符
-
返回值类型: 表示方法运行的结果的数据类型,与”return 返回值“搭配使用
-
无返回值:void
-
有返回值:可以是任意基本数据类型和引用数据类型
-
-
方法名:给方法起一个名字,要符合标识符的命名规则,尽量见名知意,能准确代表该方法功能的名字
-
参数列表:方法内部需要用到其他方法中的数据,需要通过参数传递的形式将数据传递过来,可以是基本数据类型、引用数据类型、也可以没有参数,什么都不写
-
throws 异常列表:可选,在异常章节再讲
-
方法体:特定功能的代码
-
return:结束方法,可以返回方法的运行结果
-
可以返回不同类型的数据,对应匹配的返回值类型。
-
-
- 如果方法无返回值,可以省去return,并且返回值类型为**void**
-
方法声明示例:
public class Student{ //方法: void test1(){ } void test2(int a,String b){ } String test3(){ return "abc"; } int test4(int a,int b){ return a+b; } }
4、实例方法的调用
-
方法不调用不执行,调用一次执行一次。
-
实例方法必须通过对象来调用,调用方式:对象.实例方法(【实参列表】);
-
示例:
Student stu = new Student(); stu.test1(); stu.test2(10,"abc"); String s = stu.test3(); int sum = stu.test4(11,22); System.out.println(stu.test4(1,2));
-
方法调用的注意事项:
-
形参:方法声明上的形式参数。
-
实参:调用方法时传入的实际参数。方法调用时,实参列表必须与形参列表一致。
-
方法有返回值可以通过变量接收,也可以直接输出,如果即没有接收也没直接输出会丢失返回值。
-
方法如果没有返回值不能使用变量接收,也不能直接输出。
-
-
本类内部实例变量和实例方法调用问题
public class Student{ //实例变量 String name; int age; //实例方法 public void show(){ System.out.println(name);//访问的是属性name,实例变量 System.out.println(age);//访问的是属性age,实例变量 System.out.println(this.name);//访问的是属性name,实例变量 System.out.println(this.age);//访问的是属性age,实例变量 //this代表当前对象,即谁调用此实例方法,this就代表谁 } public void hello(){ show();//直接调用本类的实例方法show方法 this.show();//通过this调用本类其他实例方法show方法 } public void test(String name){//这里使用this可以区分局部变量name和实例变量name System.out.println(name);//访问局部变量name System.out.println(this.name);//访问实例变量name } }
-
方法调用的内存分析
5、方法参数的值传递问题
-
方法参数为基本数据类型,形参的改变不会影响实参
-
方法的参数为引用数据类型,形参的改变可能会影响实参
-
特殊情况:形参为引用数据类型的String或包装类类型。
6、方法重载Overload
方法重载: 同一个类中(本类声明的或继承自父类的)的方法,方法名相同,参数列表不同的情况,这就叫方法重载。
参数列表不同: 指的是参数个数不同,数据类型不同,数据类型顺序不同。方法的重载与重写的区别 , 我有单独写一篇文章介绍 , 可以在主页找来看下
7、方法的可变参数
在JDK1.5之后, 如果我们定义一个方法时,此时某个形参的类型可以确定,但是形参的个数不确定,那么我们可以使用可变参数。
//示例
// 可变参数写法
public int getSum(int... arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
注意:
(1)一个方法最多只能有一个可变参数
(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个
8、方法的递归
-
方法的递归:方法自身调用自己的情况
-
递归的分类:
-
直接递归:方法自己直接调用自己
-
间接递归:方法间接调用自己,比如:方法A调用B,B调用A
-
-
递归的使用注意事项:
-
递归一定要有出口(结束条件),否则就是无穷递归,类似死循环。会导致内存溢出。
-
递归即使有出口,也不宜递归次数太多,否则还是会导致内存溢出。
-
-
示例:
//求n! //1*2*3*...*(n-1)*n //f(n)= f(n-1) * n //f(1)=1 public int jiecheng(int n){ if(n==1){ return 1; } return jiecheng(n-1)*n; }
-
内存分析:
六、对象数组
数组的元素是对象(引用数据类型)
//创建Student类型的数组,用于存储多个Student对象
Student[] stus = new Student[3];
Student stu = new Student();
stus[0] = stu;
stus[1] = new Student();
stus[2] = new Student();
七、封装encapsulation
-
封装:通俗的讲,封装就是把该隐藏的隐藏起来,该暴露的暴露出来。那么暴露的程度如何控制呢?就是依赖访问控制修饰符,也称为权限修饰符来控制。
便于使用者正确使用系统,防止错误修改属性 有助于系统之间的松耦合,提高系统独立性 提高软件的可重用性 降低了构建大型系统的风险
-
权限修饰符:
权限修饰符共有4种,分别为public,protected、缺省、private;权限修饰符可以使得数据在一定范围内可见或者隐藏。
修饰符 本类 本包 其他包子类 任意位置 private √ × × × 缺省 √ √ × × protected √ √ √ × public √ √ √ √ 权限修饰符可以修饰:
外部类:public和缺省
成员变量、成员方法、构造器、成员内部类:public,protected,缺省,private
-
类的封装
-
属性全部私有化
-
提供公共的get,set方法
public class Student{ //私有属性 private String name; private int age; //公共的getter和setter public void setName(String name){ this.name = name;//this表示当前对象 } public String getName(){ return name; } //..... //可以通过IDEA快捷模板生成get和set方法:alt + insert ——》选择getter,setter -->选择属性 }
-
八、继承
-
概念理解:Java类有父类和子类的区别,子类可以继承父类的成员变量和方法。
-
继承的格式:
先有父类再有子类,在定义子类时确定与父类的关系,使用关键字extends
【修饰符】 class 子类 extends 父类{ //子类成员 } //父类--超类,基类 public class Animal{} //子类-派生类 public class Cat extends Animal{}
-
继承的好处:
-
提高了代码的复用性
-
提高了代码块的扩展性。
-
是多态的前提
弊端:增强了类与类的耦合度
-
-
继承的特点:
-
子类会继承父类的所有成员变量和方法,但是不能直接访问父类的私有成员。
-
如果子类要访问父类的私有成员,可以通过提供公共的方法来访问。
-
Java类只支持单继承,即一个类只能有一个直接父类。
-
一个类可以有多个子类
-
Java类支持多层继承,一个类B可以继承自类A,C类还可以继承自B类。
-
九、方法重写Override
-
概念理解:子类中声明了与父类相同的方法,通常方法体不同。
//父类--超类,基类 public class Animal{ public void eat(){ System.out.println("动物吃饭...."); } } //子类-派生类 public class Cat extends Animal{ @Override//注解,用于验证此方法是否是重写的方法,如果不是编译失败。 public void eat(){ System.out.println("猫吃鱼...") } }
-
方法重写的具体要求:
-
子类的方法名和参数列表必须与父类的一致
-
子类方法的返回值类型必须【小于等于】父类方法的返回值类型(小于其实就是是它的子类,例如:Cat< Animal)。
注意:如果返回值类型是基本数据类型和void,那么必须是相同
-
子类方法的权限必须【大于等于】父类方法的权限修饰符。
注意:public > protected > 缺省 > private
父类私有方法不能重写
跨包的父类缺省的方法也不能重写
另外:
静态方法不能被重写,方法重写指的是实例方法重写,静态方法属于类的方法不能被重写,而是隐藏。
final修饰的方法不能被重写
私有方法也不能被重写。
-
十、多态
-
多态的理解:一个事物在不同环境或条件下呈现不同的特征状态。
-
多态的语法形式:父类引用指向子类对象
父类类型 变量 = 子类对象 Animal a = new Cat(); a = new Dog();
-
多态的表现
编译看左边,运行看右边。
Animal a = new Cat(); a.eat();//编译时看左边父类Animal中是否有eat方法,运行时执行的是右边子类Cat的eat重写的方法
-
多态的好处:
-
提高了代码的扩展性
-
降低了类与类之间的耦合度
-
-
多态的应用
-
应用在方法的参数上或成员变量
public void feed(Animal a){//形参为Animal类型,实参可以是Animal的任意子类对象 a.eat(); }
-
应用在数组
Animal[] as = new Animal[3]; as[0] = new Animal(); as[1] = new Cat(); as[2] = new Dog();
-
应用在方法的返回值类型
public Animal sale(String type){ if("cat".equals(type)){ return new Cat(); }else if("dog".equals(type)){ return new Dog(); } return null; }
-
-
向上转型与向下转型
-
子类类型对象可以自动向上转换为父类类型
-
把父类类型变量转换为子类类型,需要强制转换。但是强制转换有风险,可能发生类型转换异常ClassCastException
多态引用时,不能直接调用子类的特有方法,可以通过强制向下转型来调用子类的特有方法。
Cat cat = new Cat(); Animal a = cat;//自动向上转型 Cat c = (Cat)a;//强制向下转型 Animal a2 = new Dog(); Cat c2 = (Cat)a2;//这里运行时会发生类型转换异常。
-
-
关键字instanceof
用于判断变量或对象的运行时类型是否属于某种类型。
Animal a2 = new Dog(); //Cat c2 = (Cat)a2;//这里会发生类型转换异常。 if(a2 instanceof Cat){ Cat c2 = (Cat)a2; c2.catchMouse();//调用Cat的特有方法 }else if(a2 instanceof Dog){ Dog d = (Dog) a2; d.lookDoor();//调用Dog类的特有方法 }
-
虚方法
虚方法:就是可以被重写的方法。调用原则:编译看左边运行看右边。
-
静态分派:编译期在左边父类中找到最匹配的方法。
-
动态绑定:运行时,执行之前确定的最匹配方法的重写方法。
非虚方法:比如静态方法,final修饰的方法等不能被重写的方法,编译看左边,运行也看左边。
成员变量:编译运行都看左边,理解为不具有多态性
-
十一、构造器
-
构造器的作用:用于new对象时为实例变量赋值。
-
构造器的语法格式:
【权限修饰符】 类名(【参数列表】){ //构造器体 }
public class Student{ //属性 String name; int age; //空参构造器 public Student(){} //有参构造器 public Student(String name,int age){ this.name = name; this.age = age; } }
格式说明:
-
修饰符只能是权限修饰符
-
构造器名称必须与当前类名相同
-
构造器类似方法,所以也称为构造方法
-
构造器没有返回值,void也不能有。
-
构造器可以重载
-
-
构造器的使用
new 构造器名(【参数】); Student stu = new Student();//使用空参构造器创建对象 Student stu2 = new Student("tom",18);//使用两个参数的构造器创建对象
使用说明:
-
每个类中默认自带一个空参构造器。
-
一旦显示给出一个构造器,默认的空参构造器不再存在。
-
构造器不能继承
-
-
this和super调用构造器
-
this(【参数】) :用于调用本类的其他构造器,必须用在构造体内第一行
-
super(【参数】):用于调用父类的构造器,必须在构造体内第一行
-
通过构造器创建子类对象时,一定会先调用父类构造器初始化父类数据。
-
每个构造器内默认自带super()用于调用父类构造器。当显示给出this(【参数】)或者super(参数)时,默认的super()不再存在。
-
十二、非静态代码块(了解)
-
作用:跟构造器一样通常是为实例变量赋值
-
格式:在类中定义{}
public class Student{ String name; int age; //非静态代码块-实例化代码块 { //为实例变量赋值的代码 } }
-
执行特点:
调用任意一个构造器都会执行。并且一定优先于构造器执行。
十三、实例初始化过程(了解)
-
实例初始化过程:即创建对象的过程,主要是为实例变量赋值的过程。
-
实例初始化方法:
当通过构造器new对象时。代码底层会执行一个实例初始化方法init{},调用任何一个构造器都会执行此次方法,此方法包含4部分内容:
-
构造器内第一行super(【参数】)
-
实例变量的直接显示赋值语句
-
非静态代码块中语句
-
构造体内其余代码
执行过程:首先执行的一定是super(【参数】),2,3部分按照代码书写顺序执行。最后执行构造体内其余代码。
-
十四、this和super关键字
-
this关键字:
表示当前对象
-
应用在实例方法,构造器等地方
-
使用方式:
this.实例变量或实例方法 :表示调用当前对象的实例变量或方法
this(【参数】) :表示调用本类的其他构造器
-
-
super关键字
用于访问父类数据的一个关键字
-
应用在实例方法、构造器等地方
-
使用方式:
super.实例变量或实例方法 :表示调用父类的成员
super(【参数】) :表示调用父类的构造器
-
-
this和super访问成员变量和方法遵从原则:
就近原则和追根溯源原则
十五、native和final关键字
-
native关键字
本地的,用于修饰方法,是本地方法,方法体是c/c++编写,我可以直接调用或重写。
-
final关键字
最终的,不可修改的
-
修饰变量是常量
-
修饰的方法不能被重写
-
修饰的类不能被继承
//此类不能被继承 public final class Student{ //此方法不能被重写 public final void test(){ //此变量是常量 final int x = 10; } }
-
十六、Object类
java.lang.Object类是根父类,即是所有Java类的父类。
常用方法:
-
int hashCode(); 返回对象的哈希值,此方法是为了提高哈希表性能。
此方法默认返回是对象的内存地址转换而来的一个整数。建议子类重写此方法,使其返回值与对象的属性相关。
-
Class getClass(); 返回对象的运行时类型。
对象.getClass().getName() 返回对象的运行时类型名称(字符串)
-
String toString(); 返回对象的字符串形式。即把对象转换为字符串返回。
默认返回的是对象的运行时类型名称+'@'+对象的哈希值的16进制形式
建议所有Java类都重写此方法,用于返回对象的属性信息。
System.out.pritnln(对象)等价于System.out.pritnln(对象.toString())
-
boolean equals(Object obj); 此方法用于比较两个对象是否相等
默认此方法用于比较两个对象的内存地址是否相等。
建议子类重写此方法,用于比较对象的内容是否相同。
-
void finalize();此方法由垃圾回收器调用,通常用于释放一些c/c++占用的释放资源。
十七、标准JavaBean
编写Java类的一般标准规范。
-
类应该是具体的,公共的
-
应该提供无参构造器
-
属性应该私有化,并提供公共的getter,setter方法
-
实现序列化接口Serializable
十八、静态static
静态是随着类的加载而加载。
-
成员变量
-
静态变量-类变量:有static修饰
是所有对象共享的一份数据,通常通过类名来访问,类名.静态变量,存在内存的方法区
-
非静态变量-实例变量:没有static修饰
是每个对象独有一份实例变量值,必须通过对象来访问,对象.实例变量,存储在堆中
-
静态类变量和非静态实例变量、局部变量
静态变量 实例变量 局部变量 声明的位置 直接声明在类的成员位置 直接声明在类的成员位置 声明在方法体中或其他局部区域内(方法声明上,构造方法,代码块等) 修饰符 必须static,还可以public、private、final等 可以public、private、final等 不能使用访问权限修饰符,可以使用final 内存位置 方法区 堆 栈 初始化值 有默认初始化值 有默认初始化值 无默认初始化值 生命周期 和类相同 同对象的生命周期 随着方法的调用而存在,方法调用完毕即消失
-
-
静态方法
有static修饰的方法是静态方法,或称为类方法
-
访问方式:
静态方法建议通过类名直接访问,类名.静态方法,不推荐使用对象访问。
实例方法必须通过对象来访问
-
特点:
静态方法不能被重写,称为覆盖。
静态方法在多态引用形式下,编译运行都看左边父类类型。
-
-
静态代码块
static修饰的代码块,通常用于为静态变量赋值等
执行特点:在类加载过程中执行,并且只执行一次,优先于非静态代码块的执行。(非静态代码块new调用构造器时就会执行,每次调用都会执行)
public class Student{ //静态变量 static int x; //静态代码块 static{ x = 123; } }
-
类的初始化
类的初始化只在类加载过程中完成的,类初始化的目的主要是为静态变量赋值。类初始化时会在底层执行一个clinit{},此方法包含2部分内容:
-
静态变量的直接显示赋值语句
-
静态代码块中语句
这两部分代码块按照书写先后顺序执行。
注意:
-
类的初始化只执行一次,并且优先于实例化。
-
一个类要初始化,如果其父类还未初始化先初始化父类。
-
-
本类内静态与非静态相互访问问题
-
静态不能直接访问非静态
-
this和super是与对象相关的,不能使用在静态域中
public class MyClass{ static int x = 10;//静态变量 int y = 20;//非静态变量 //实例方法 void testInstance(){ System.out.println("实例方法..."); } //静态方法 static void testStatic(){ System.out.println("静态方法..."); } //实例方法 void test1(){ System.out.println(x); System.out.println(y); testInstance(); testStatic() } //静态方法 static void test2(){ System.out.println(x); // System.out.println(y);//不能直接访问非静态变量 // testInstance();//不能直接访问实例方法 testStatic() //System.out.println(this);不能使用this //super.toString();//不可以使用super } }
-