面向对象(思想)
权限修饰:
- public: 公开的,所有不同的包,不同的类全都可以访问得到。
- private: 私有的,只有自己的类(同一个class)中可以访问,其他的都访问不到。
- protected: 受保护的,除了不同包的其他类访问不到,其他都可以访问到,不同包的子类也可以 访问的到。
- 默认:只有同一个包中的类可以访问到,不同包访问不到。
封装:
-
实际含义是:该隐藏的隐藏,该暴露的暴露
-
全局变量:定义在类中的,所有方法都可以访问到,叫全局变量
-
局部变量:定义在一个方法里的,只有本方法可以访问的叫局部变量
定义变量:
? 权限修饰符(public) + 类型(void、int、string、array[]...) + 变量名称
注:变量名称要用合法的JAVA标识符,首单词的第一个字母小写,后面的每一个单词首字母大写
可变参数:
public static void test(int...a){
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
-
当不确定参数内要传多少个时,用int... 在调用test方法时,可以任意传几个参数,同时会把a当作数组进行处理
-
注:
-
如果一个参数里有可变参数,并且有多个参数,那么可变参数一定要放在最后一个
-
public static void test(int b,int...a){ for(int i=0;i<a.length;i++){ System.out.println(a[i]); } }
-
方法封装:
- -定义格式: 修饰符(private) + 返回值类型(void、int、string....) + 方法名(自定义)+
( 参数类型 参数名称 + , + 参数类型 参数名称) + { 代码体 + return 表达式 }
-
形式参数:在参数名称中,方法本身起的名字叫形式参数,只起一个代号的作用。
-
实际参数:在通过 . 调用方法时,依据形式参数传进的东西是实际参数。
-
不需要new对象就可以访问的方法封装:
? public static Person getPerson(){
? return new Person();
? }
-
方法封装的好处:1.方便维护 2.减少冗余代码的出现
构造方法:
-
作用:用于该类的实例对象的初始化
-
格式: public Person(){ }
-
示例: pubilc int size;
? pubilec Person(){
? size=18;
? }
- 这就是给对象做了初始化,只要在另一个类中调用了Person的方法,new出了Person,那么当输出size时,默认输出18.
- 构造方法中也可以传参数,当传入了参数后,再调用此方法是就必须传进参数对应的类型,如果想既可以传参数,也可以不传参数,那么就再构造一个同名的方法,该方法不加任何参数,这就叫构造方法的重载
This关键字
-
this关键字总是指向该方法的对象。
- 当this出现在构造方法中,this指的是该构造器正在初始化的对象,(也就是最外层的)
- 在普通方法中引用,this指的是调用该方法的对象
-
作用:this关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或Field
final关键字
-
final关键字可以修饰类,可以修饰变量,可以修饰方法:
-
修饰类,类不能被继承
-
修饰变量,变量就变成了常量,只能被赋值一次 当修饰的变量是一个对象时,该对象不能改变(即不能将变量更改为另一个对象),但是对象中的内容可以改变
-
如:final StringBuffer a=new StringBuffer("abc");
? 执行 a=new StringBuffer(""); 会报错,因为又重新New了一个对象
? 但是执行 a.append("123"); 不会报错,因为对象没有改变,对象的内容发生变化是不影响的
-
-
修饰方法,方法不能被重写
-
通过set方法对对象进行初始化:
代码: public void setSex(String sex){
? this.sex=sex;
? }
小结:
- 变量—————— 类对应的属性
- 构造方法——————new对象的时候对对象初始化
- 方法(函数)——————功能性的方法
封装打包学生类的代码:
Demo demo=new Demo();
Student student=new Student("tom",18,6,"3333","男");
demo.save(student);
public void save(Student student){
? System.out.println(student.getName());
? System.out.println(student.getAge());
}
匿名对象
如上:Demo demo=new Demo();
? demo.save(new Student());
- new Student只用到一次,没有给他起名字,这就是匿名对象
值传递
-
JAVA的参数传递方式只有一种,那就是值传递
-
值传递含义:就是将实际参数的复制品传进方法,也就是重新创建一个一模一样的参数,对这个复制品进行方法操作,而实际参数的本身并没有受到影响。
如:int a=5,b=5;
? public void change(int a, int b){
? a=100;? b=100;
? }
public void change(int a, int b){ a=100; b=100; } public static void main(){ int a=10; change(a); System.out.println(a); } //打印后a的值依旧是10,调用方法并没有改变,因为传进去的是基本类型的副本,只有引用类型才会传进地址,最后的值会被改变,如果用change方法改变a的值的话,需要在后面return
传进的是引用类型时:
-
public void change(StringBuffer buffer){ buffer.append("123"); } public static void main(){ StringBuffer buffer=new StringBuffer("ABC"); change(buffer); System.out.println(buffer); } //此时打印后结果为ABC123,因为传进去的是地址,原本的值会被修改
在此次方法操作中,a和b的值依旧是5,并没有变成100,就是对a与b的复制品进行了操作,实际参数本身没有改变
如果想要将ab变成100的话,就需要返回a与b,在后面加return ,并将void改为Int
-
-
只有基本类型的值传递才是将复制品传进方法,其他类型的值传递是传进地址值的复制品,所以是可以对实际参数进行修改的
重载
-
方法名不可以重名,但是方法名相同时,参数列表不同时,如:方法一有两个参数,方法二有三个参数,尽管两个方法名字相同,但是可以同时存在,这叫方法的重载
-
重载只与方法名和参数名称有关,与权限修饰符,返回值类型等无关
-
方法名相同,参数名称不同或参数数量不同时,才叫重载
递归
-
含义:自己调用自己
-
斐波那契数列:
-
1 1 2 3 5 8 13 21 34
-
假设要求第n位的值:
public int fb(int n){
? if(n1 || n2){
? return 1;
? }else{
? return fb(n-1)+fb(n-2);
? }
}
-
-
递归最重要的是找到第一个递归的出口
Static
-
特点:
-
static是跟随类的出现而出现,类名出现一次,那么static后面的内容就会执行一次
-
被类的所有对象(new一次就是一个对象)共享:在调用static修饰的变量时,不同对象调用的是同一个变量,对象一对变量b进行改变时,对象二中的变量b也会改变而不同的对象调用不被static修饰的变量时,不同的对象使用的是不同的变量,对象一修改变量a时,对象二的变量a是不会被改变的
-
例如:
-
static int a=1; public static void main(){ Num num1=new Num(); Num num2=new Num(); num1.a=2; System.out.println(num2.a) } //此时打印的num2的a,它的值为2,因为两个对象共用的一个变量,num1做了修改,num2也会有改变
-
-
可以通过类名直接调用
-
-
注意事项
- 在静态方法中不可以使用this关键字 因为this关键字总是指向该方法的对象,静态方法是随着类的出现而出现,不需要New出对象,所以在静态方法中,没有对象是无法使用this的
- 静态方法里不能访问成员变量或成员方法 因为静态方法是随着类的出现而出现,成员变量需要先New出对象,才能访问得到
-
静态变量和成员变量的区别
- 所属不同
- 静态变量属于类,所以也称为为类变量
成员变量属于对象,所以也称为实例变量(对象变量) - 内存中位置不同
静态变量存储于方法区的静态区
成员变量存储于堆内存 - 内存出现时间不同
静态变量随着类的加载而加载,随着类的消失而消失
成员变量随着对象的创建而存在,随着对象的消失而消失 - 调用不同
静态变量可以通过类名调用,也可以通过对象调用
- 静态变量属于类,所以也称为为类变量
- 所属不同
-
用武之地
- 使用工具方法时,可以加static,因为每次使用工具都需要New出对象,过于麻烦,而加上static后,只需要使用类的名字直接用点就可以调用,不需要new对象
- 只需加载或执行一次
代码块:
-
局部代码块:
- 出现在方法的内部,用大括号括起来的就是局部代码块
- 定义在局部代码块内的变量,出了局部代码块后,外面的访问不到
- 限定变量生命周期,及早释放,提高内存利用率
-
构造代码块
- 在类中方法外出现;多个构造方法中相同的代码存放到一起,每次调用构造都执行时就可以用构造代码块,并且在构造方法前执行
- 运用:当所有的构造方法中都有相同的部分时,可以把他放进构造代码块里,这样可以减少构造方法中相同的部分出现
-
静态代码块
- 在构造代码块前加上static,构造代码块是New一次,代码块的内容出现一次,静态代码块是类出现一次,就执行一次
继承:
概述:
-
多个类存在相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为(也叫方法),只要继承这个类就可以了,这个类就是父类
-
父类与子类:
- 父类又叫超类或者基类
- 子类又叫派生类
-
通过extends关键字实现继承
- class 子类名 extends 父类名 {}
继承的好处:
-
提高了代码的复用性
- 多个类相同的成员可以放到同一个类中
- 如:老师和学生同属于人,那么人这个类中定义的姓名,年龄,身高体重这些属性老师和学生都可以使用
-
提高了代码的维护性
- 如果功能的代码需要修改,只需修改父类的代码即可
-
让类与类之间产生了关系,是多态的前提
- 其实这也是继承的弊端,类的耦合性很强
- 耦合性:在A类中new一个B类,一旦B类出现问题,那么A类中使用的B类也不能用,或者想要将B类换成C类,要将A类中所有B类的部分全都替换
特点:
-
JAVA只支持单继承,不支持多继承
- 一个类只能有一个父类
-
JAVA支持多层继承(爷爷类)
- A继承B B继承C
注意事项:
-
子类只能继承父类非私有的成员(成员方法和成员变量)
- 这也是继承的另一个弊端:打破了封装性
-
子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法
-
要访问父类的构造就只能通过子类的构造方法去访问
-
//父类的空参构造: public Pet(){ } //通过子类访问父类构造: public Dog(){ super(); } //注:尽管在子类的构造方法中没有写super(); 但是已经默认写上了父类的空参构造 //父类的有参构造: public name; publci Pet(String name){ this.name=name; } //通过子类访问父类的有参构造: public Dog(String name){ super(name); }
-
-
子类中所有的构造方法默认都会访问父类空参的构造方法
- 因为要实现子类的初始化,首先要实现父类的初始化,子类使用的是父类的变量,父类如果没有构造,子类不能使用
-
不能通过 子类=new 父类
-
可以通过 父类=new 子类
-
子类中访问变量的顺序
- 首先在子类局部范围找
- 然后在子类成员范围找
- 最后在父类成员范围找 不能访问父类局部范围
- 最后还没有就会报错 是不会找爷爷类的
super关键字
-
super的用法和this很像
- this代表本类对象的引用
- super代表父类对象的引用
-
super用法:
- super.变量名 (父类的变量) super.name;
- super.方法名 (父类的方法) super.eat();
重写(Override):
-
子类中出现了和父类一模一样的方法声明,也被称为方法覆盖,方法复写
-
规则:
-
方法名相同,形参列表相同
-
子类方法返回值类型应该比父类方法返回值相等或者更小。
- 返回值类型比父类的要小,这两个返回值一定要有父子关系才行
- 基本类型之间没有父子关系
-
子类方法声明抛出的异常应该比父类方法更小或者相等
-
子类权限比父类权限大或者相等
-
-
补充:
- 子类重写了父类的方法后,子类对象无法访问父类中被覆盖的方法,但可以在子类方法中调用父类被重写的方法,需要使用super关键字
- 如果父类的方法啊具有private权限修饰符,则该方法是对子类隐藏的,也就是无法重写该方法
- 如果子类中定义了一个与父类private方法 相同的方法名、形参列表、返回值类型,这依然不是重写,只是在子类重新定义了一个新方法而已
-
子类重写父类方法时,访问权限不能更低
- 如:父类方法用 protcted修饰,那么子类的修饰符只能更大或者一致,也就是只可以用public 或者protcted修饰
- 父类静态方法,子类也必须经过静态方法进行重写
- 这个不算重写,但是表现出的现象确实如此
- 因为静态不属于继承的范围,静态与类挂钩,与对象无关
常量的权限修饰:
- 任何一个常量都是被public static final修饰
- public 保证可以访问到
- static 表示是跟着类出来的 (通过类来选)
- final 表示不能更改
一个类的初始化顺序:
- 先初始化静态变量,静态方法
- 执行静态代码块
- 执行构造代码块
- 执行构造方法
多态
- 一个事物在不同时刻表现出来的不同状态
多态的前提和体现:
-
有继承关系
-
有方法的重写
-
有父类引用指向子类对象
-
举例:
-
Pet pet=new Dog(); pet.eat(); Pet pet=new Cat(); pet.eat();
-
new Dog时打印出狗吃骨头,new Cat时打印出猫吃鱼
-
多态的好处:
-
对外管理的是同样的pet对象,具体New哪一个类,在后面改就可以
- 在大型项目中,后面用父类具体new哪一个子类,是不用在代码里写的,用配置文件配置就好了
- 这叫做解耦,代码与代码之间的耦合性降低
-
提高了程序的维护性
-
提高了程序的扩展性
- 在定义方法时,传进的参数只需传一个父类就代表随意传子类了,具体想要传哪一个子类,只需在父类new子类的时候,改成想要new的那个子类就可以,形参是不需要动的
多态的弊端:
- 不能访问子类特有功能
- 想要访问子类特有功能只能转型
instanceof关键字
-
A类 instanceof B类
- A类是否是B类的子类
-
A类 instanceof A类
- 这也是可以的
成员访问的特点:
-
访问变量时,访问的是父类的变量
-
访问方法时,访问的是子类的方法
-
但是父类中要有和子类方法一样的方法名
-
如: 子类Dog类中有play这个方法,但是父类Pet类中没有该方法,所以是无法使用Dog类的play方法的
-
这就是多态的弊端:无法访问子类特有的功能
- play方法是Dog类特有的功能,父类Pet类没有,所以访问不到
-
解决方法:转型
-
public static void change(Pet pet){ if(pet instanceof Dog ){ pet=(Dog)pet; ((Dog)pet).play(); } if(pet instanceof Cat){ pet=(Cat)pet; ((Cat)pet).play(); } }
-
-
-
-
访问静态方法时,访问的是父类的
抽象类
-
抽象就是找出事物的相似和共性之处,然后将然后将这些事物归为一个类,这个类只考虑这些
事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与
当前目标有关的方面 -
当一个类没有具体信息,只是定义一些功能(就是要干嘛能干嘛),那么就把这个类定义为抽象类
定义格式:
- 抽象类和抽象方法必须用abstract关键字修饰
- abstract class 类名 {}
- public abstract void eat();
特点:
-
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
-
抽象类中有具体方法,是为了提高代码的复用性
- 抽象类可以有一些共有的工具方法,这些方法对所继承的所有子类来说都是一样的,或者是不变的、唯一的,那么就可以加在抽象类中大家一起去用
- 子类所特有的一些东西,在抽象类中只定义一个抽象方法,具体的实现由子类自己去重写
-
抽象类中有具体方法,是为了提高代码的复用性
-
抽象类不能够被实例化
- 抽象类的实例化是通过多态来实例化
- 这也是多态的一种,抽象类多态
-
抽象类的子类:
- 抽象类的子类必须重写抽象类的所有抽象方法
- 如果子类没有实现抽象父类的所有抽象方法,那么子类也必须定义为抽象类
成员特点:
-
成员变量:
- 可以是变量
- 可以是常量
-
构造方法:
- 抽象类可以有构造方法,但是不能够被实例化
-
构造方法的作用就是用于子类访问父类数据的初始化
- 抽象类的抽象方法是要被子类重写的,是要有继承关系的,所以抽象类的构造方法的作用就是让子类去访问的,但是抽象类本身是不能够被实例化,不能new出抽象类这个对象,但是它的构造方法会被执行一下
- 抽象类不能有抽象构造方法和抽象静态方法
-
成员方法:
- 抽象方法:限定子类必须完成某些行为
- 非抽象方法:提高代码的复用性
abstract关键字不能与哪些关键字共存:
-
private 冲突
- 定义为抽象方法一定是要被子类重写的,那么如果将抽象方法定义为private子类都访问不到,重写个锤子
-
final 冲突
- 与上同,final修饰的方法不可以被重写
-
static 无意义
- 抽象类要被继承,继承与对象挂钩,对象是后出现的,而static是随着类的出现而出现,继承不到static方法
接口
- 接口是在抽象类的基础上出现的,接口限定的是行为,方便代码的扩展
格式:
-
定义一个类为接口:
-
public interface UserService{ public void insert(); public void delete(); }
-
-
用一个类实现一个接口:用 implements
-
public class UserService implements UserService{ public void insert(){ } public void delete(){ } }
-
特点:
-
对于变量来说:
- 只能是常量
-
且常量的默认修饰符:public static final
- 接口是一个规范,是不能被改变的,所以一定是常量,被final修饰,如果可以更改的话,这个规范没有意义,就不叫规范
-
对于方法来说:
- 只能是抽象方法
- 且抽象方法的默认修饰符:public abstract
-
对于构造方法:
- 接口没有构造方法
- 接口主要做功能拓展的,没有具体实现
-
接口不能被实例化
- 要实例化接口,就要按照多态的方式
- 这也是多态的一种,叫接口多态
-
接口的子类
- 必须重写接口中的所有抽象方法
接口和抽象类的差异
-
抽象类是一个类,子类要继承(extends)它, 接口是要被子类实现(implements),关键字不同
-
对于变量:
- 抽象类可以有普通成员变量,接口没有普通成员变量
- 接口的变量只能为常量,默认被public static final修饰
- 抽象类可以有普通成员变量,接口没有普通成员变量
-
对于成员方法:
- 抽象类里可以有非抽象的方法,但是接口里必须全都是抽象方法
- 抽象类的方法可以包含静态方法,接口不能包含静态方法
- 接口的抽象方法只能是,并且默认是:public abstract
-
对于构造方法:
- 抽象类可以有构造方法,接口不能有构造方法
-
一个类可以实现多个接口,但只能继承一个抽象类