面对对象
一.对象基础
1.对象的概念
1.1 万物皆对象,客观存在的事物都是对象
2.类
2.1 什么是类?
类定义了一种抽象数据类型
类就是模板,确定对象将会拥有的特征(属性)和行为(方法)
2.2 类的特点
-类是对象的类型
-具有相同属性和方法的一组对象的集合
3.什么是对象的属性
属性-对象具有的各种特征
每个对象的每个属性都拥有特定值
例如:手机类
属性:屏幕尺寸,CPU,内存。。。
注:对象的属性拥有默认值,这个默认值与相应的类型对应
例如:int默认值为0,boolean默认值为false,引用类型默认值为null
4.什么是对象的方法
方法-对象执行的操作
5.类与对象的关系
类是抽象的概念,仅仅是模板,在现实世界中是不存在的,而对象是一个你能够看得到,摸得着的具体实例
例如:
手机类:
属性:屏幕,CPU,内存
方法:打电话,发短信
对象:华为荣耀,小米等。。
6.实例化对象
格式:文件名 实例化对象名=new 文件名();
举例: Dog a = new Dog();
实例化Dog这个类
dog是Dog类实例化的对象
7.对象的内存模型
实例化对象Dog a和Dog b 是两个不同的存储空间
8.静态方法的调用
静态方法可以通过类名.方法名的方式调用
但是不能通过类名.方法名的方式调用非静态方法
举例:Car.run();
9.非静态方法的调用
可以通过类的实例化队形名.方法名的方式调用静态方法
也可以通过类的实例化队形名.方法名的方式调用非静态方法
举例:Car car = new Car();
car.run();
car.Massage();
10.成员变量与局部变量
- a)作用域不同
* -局部变量的作用域仅限于定义他的方法
* -成员变量的作用域在整个类内部都是可见的
* b)初始值不同
* -成员变量有默认的初始值
* -局部变量没有默认的初始值,必须自行设定初始值
* c)同名变量不同
* -在同一个方法中,不允许有同名的局部变量
* -在不同的方法中,可以有同名的局部变量
* d)存储位置不同
* -成员变量是在对象创建以后存在于堆中,对象回收时,成员变量消失
* -局部变量是在方法被调用是存在于栈中,方法调执行结束,从栈中删除
* e)生命周期不同
* -对象的创建而创建,对象回收时,成员变量消失
* -随着方法的调用被创建,方法执行结束,从栈中清除
*
11.静态成员变量(跨对象共享变量)
public static int y;
这个y就是静态成员变量
12.匿名对象
举例:new Person04().sunflower();
*普通变量 直接赋值
*引用变量 引用了一个内存地址
*匿名变量 没有引用类型变量指向的对象
*优点:使用之后直接从内存中消失,不会长期占用内存 适用于仅仅偶尔使用的场景下
*缺点:因为使用之后直接从内存中消失 如果频繁使用该对象 需要频繁的创建和删除该对象 创建和删除都要消耗系统资源 建议频繁使用的对象尽量使用引用类型变量
二.对象属性赋值与读取
赋值:对象的赋值就是在对象实例化后将数值赋值给实例化的那个变量
举例 :person01.nickname = “李昊哲”;
这个李昊哲就是赋值给person01.nickname这个对象的值
读取: 直接输出这个实例化对象名即可
System.out.println(person01.nickname);
1.访问修饰符 (public protected default private)
java中可以用访问修饰符来保护对类,变量,方法和构建方法的访问,java支持4种访问修饰符
public :对所有类都可见 使用对象:类,接口,变量,方法。
protected : 对同一包内的类和所有子类可见。 使用对象:变量,方法。 注意:不能修饰外部类
default(即默认,什么也不写): 在同一包内可见,不使用任何修饰符。 使用对象:类,接口,变量,方法。
private :仅在同一类中可见 使用对象:变量,方法。 注意:不能修饰外部类
2.封装
即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别
代码举例:
private String nickname; //建立一个字符串变量 nickname
public void setNickname(String name) { //将字符串赋值给name这个参数
nickname = name;
}
public String getNickname() { //返回nickname实现封装
return nickname;
}
输出:
Person02 person01 = new Person02(); //对象实例化
person01.setNickname("沸羊羊"); //给name传输字符内容 并且赋值给了nickname
System.out.println(person01.getNickname()); //输出getNickname然后return nickname的值
3.封装中this的含义
this 方法的调用者 谁调用我 我就是谁
this 在此处的含义就是调用该类中的成员变量
举例:
private String nickname;
public void setNickname(String nickname) { //这里的this.nickname实际是调用了成员变量的那个nickname
this.nickname = nickname;
}
public String getNickname() {
return nickname;
}
三.构造方法
方法名与类名相同 方法体没有返回值 但是再方法声明的时候却也不需要使用void修饰的方法我们称之为构造方法
构造方法的作用 用于初始化对象 对象的属性赋值
1.无参构造方法
没有参数的构造方法我们称之为无参构造方法
注意当一个类中 既没有无参构造方法也没有有参构造方法的时候jvm会追加一个无参杓造方法
但是当一个类中 存在有参构造方法没有编写无参构造方法的时候jvm不会追加无参构造方法
所以不论在任何情况下一定要自己手写有一个无参构造方法
2.有参构造方法
有参数的构造方法我们称之为有参构造方法
举例:public Person01(String nickname,int gander,int age) {
this.nickname = nickname;
this.gander = gander;
this.age = age;
这个结构方法中有参数所以是有参构造方法 并且再实例化的时候直接可进行赋值参数
Person01 person01 = new Person01("黑小虎", 1, 51);
3.利用lombok功能实现快捷构造方法
@NoArgsConstructor 无参构造方法
@AllArgsConstructor 全参构造方法
4.构造代码块
花括号包裹起来的代码 我们称之为代码块或者代码段
只有一对花括号包裹其来的代码 我们称之为构造代码块
构造代码块与构造方法一样都是在类被实例化的过程中被调用的
执行顺序: 构造代码块>>>构造方法
类每次被实例化的过程中都会调用构造代码块
举例:{
System.out.println("我是构造代码块");
}
后续在对象实例化的时候 每实例化一次就输出一次“我是构造代码块”
5.静态代码块
使用static 修饰的构造代码块 我们称之为静态代码块
当类在被加载的时候就执行静态代码块 而且静态代码块 只执行一次 不可多次执行
而构造代码块是在对类实例化的过程中执行的
执行优先级 静态代码块>>>构造代码块>>>构造方法
6.包装类
jdk1.5 提出包装类
包装类对象>>>基本数据类型 拆箱
基本数据类型>>>包装类对象 装箱
JDK1.5 自动装拆箱
//Byte byte
//Short short
//Long long
//Integer int
//Double double
//Float float
//Character char
//Boolean boolean
四.继承(父类与子类)
1.继承的概念
概述:多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类中, 那么多个类无需再定义这些属性和行为,只需要继承那个类即可
多个类可以称为子类,单独这个类称为父类或者超类,基类等。
子类可以直接访问父类中的非私有的属性和行为。
通过extends关键字让类与类之间产生继承关系。
2.super关键字
super可以理解为是只想自己父类的一个指针,而这个父类指的是离自己最近的一个父类。
super普通的直接引用与this类似,super相当于是只想当前对象的父类,这样就可以用super.xxx来引用父类的成员
举例:
public Male(String nickname, int gander, int age) {
super.setNickname(nickname); //接受到下面返回来的参数再传输给父类的属性
}
Male male = new Male("盈盈",1,4); //有参构造方法 返回参数
3.子类实例化其实是先实例化父类
通过代码举例验证 子类和父类同时输入无参构造方法
结果输出顺序是 :person01的无参构造
Male的无参构造
所以:子类实例化其实是先实例化父类
4.子类可以拥有自己独有的构造方法
5.方法重写
Override 重写
当父类方法满足不了子类的需求的时候,子类可以重写父类的方法 这种表现形式我们称之为方法的重写
6.向上转型
父类对象的引用指向了子类对象的实例化对象
举例:Person01 male = new Male();
male.eat(); //此时调用的是male中重写后的eat 并且eat换成male中独有的方法也是不可执行的
7.向下转型
和数据类型差不多 小转大自动转 大转小强制转
举例:Person01 Person01 = new Male();
Male male = (Male) Person01;
Person01.eat();
male.eat();
你这个方法能不能调 你得看你真正的类型是谁
8.重载看参数的数据类型 重写new的对象
方法重载与方法重写的区别
在同一个类中,参数列表不同的同名方法我们称之为方法重载
父类的方法满足不了子类需求,子类重写父类的方法 我们称之为方法重写
方法重载在同一个类中而方法重写必须存在于父子继承关系
9.this 调用构造方法
this 在构造方法中调用其他构造方法只能放在第一行
注意 使用this调用构造方法的时候不能相互调用 避免造成死循环
10.super 调用父类构造方法
举例:super(nickname,gender,age);
super调用父类的构造方法的时候 只能放在第一行
11.抽象方法与抽象类
使用abstract修饰没有方法提的方法 我们称之为抽象方法 具备抽象方法的类必须是抽象类
使用abstract修饰的类 我们称之为抽象类 抽象类不一定必须有抽象方法 但是抽象方法必须有抽象类
子类继承抽象类 第一种写法是重写抽象类中的抽象方法 子类继承抽象类 第二种写法是子类也是个抽象类
举例:public abstract class Person01 {
public abstract void eat();
}
12.final 修饰方法
使用final修饰的类不能被继承也不能被重写
final 意思上就是 最终的意思 被final修饰的类就是最终的类 所以不能被继承也不能被重写
五.内部类
1.静态成员内部类
举例:public class Outer01 {
public static class Inter{
public static void eat() {
System.out.println("造他就完了");
}
}
}
输出:Outer01.Inter.eat();
2.非静态成员内部类
如果成员内部类是非静态类加静态方法的话 依然可以直接 外部类.内部类.方法 去调用这个方法
但是如果内部类是非静态类加非静态方法的话 就需要实例化非静态成员内部类 new 外部类().new 内部类().方法
非静态类加静态方法举例:public class Outer02 {
public class Inner{
public static void eat() {
System.out.println("造他就完了");
}
}
}
输出:Outer02.Inner.eat();
非静态类加非静态方法举例:public class Outer03 {
public class Inner{
public void eat() {
System.out.println("造他就完了");
}
}
}
输出:new Outer03().new Inner().eat();
3.利用方法调用非静态成员内部类中的方法
举例:public class Outer04 {
public class Inner{
public void eat() {
System.out.println("造他就完了");
}
}
public void innereat() {
new Inner().eat(); //在外部类下建立一个非静态方法去直接调用上方内部类里的方法 然后在外边直接调用此方法即可
}
}
输出:new Outer04().innereat();
4.静态方法调用及局部内部类静态方法
举例:public class Outer05 {
public static void innereat() {
class Inner {
public static void eat() {
System.out.println("造他就完了");
}
}Inner.eat();
}
}
输出:Outer05.innereat();
5.静态方法调用及局部内部类非静态方法
举例:public class Outer06 {
public static void innereat() {
class Inner {
public void eat() {
System.out.println("造他就完了");
}
}new Inner().eat(); //这两个区别就是 方法变成了非静态 变成非静态不要慌 new他就完了
}
}
输出:Outer06.innereat();
6.非静态方法调用及局部内部类非静态方法
举例:public class Outer07 {
public void innereat() {
class Inner {
public void eat() {
System.out.println("造他就完了");
}
}new Inner().eat();
}
}
输出:new Outer07().innereat(); //还是那句话 变成非静态不要慌 new他上面那个类就完了
7.局部内部类匿名对象
内部类里面没有方法 在通过实例化的过程中 直接写出并调用方法 叫局部内部类匿名对象
举例:public class Outer08 {
public void innereat() {
class Inner {
}
new Inner() {
public void eat() {
System.out.println("造他就完了");
}
}.eat();
}
}
8.匿名内部类
在写匿名方法的时候 这个实例化的对象 必须是要存在的
这个时候我们可以输入new Object 因为Object 是个超类 相当与最大的类 这种写法我们称之为匿名内部类
举例:public class Outer09 {
public void innereat() {
new Object() {
public void eat() {
System.out.println("造他就完了");
}
}.eat();
}
}
六.多态
1.多态概念
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作。
多态性是对象多种表现形式的体现。
举例:现实中,比如我们按下 F1 键这个动作:
如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
如果当前在 Word 下弹出的就是 Word 帮助;
在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
多态的优点:
1.消除类型之间的耦合关系
2.可替换性
3.可扩充性
4.接口性
5.灵活性
6.简化性
多态存在的三个必要条件:继承 重写 父类引用指向子类对象 Parent p = new Child();
2.继承方式实现多态
父类为抽象类抽象方法 子类通过重写来实现多态
3.接口实现多态
接口通常以interface来声明,一个类通过继承接口的方式,从而来继承接口的抽象方法
实现多态的形式:父类以interface来声明接口并在接口下声明方法,子类以implements 来实现(继承)接口内的方法
implements 实现举例:public class Dogporson implements Dog ,Person{
@Override
public void eat(){
System.out.println("hihihi");
输出:Dog dog = new Dogporson(); //父类实例接口指向子类
dog.eat();
4.接口可以多继承
举例: 接口类:public interface Fa03 extends Fa01,Fa02{
void fa03fun(); //每个接口里面都有一个方法 Fa03这个接口同时继承了01和02这两个接口
实现类:public class Fa03Impl implements Fa03{
输出: Fa03 fa03 = new Fa03Impl();
fa03.fa01fun();
fa03.fa02fun(); //接口通过实现 只能调自己接口内的方法
fa03.fa03fun(); //但是通过继承的03方法可以调用继承过来的01,02接口内的方法
5.接口中只能声明常量 而且是静态常量
6.接口中用default和static修饰的方法
首先正常来说接口中的方法是不允许有方法体的,如果需要方法体那么需要用default和static修饰方法
default和static的区别:
1.调用方法:default是使用实现类的实例化对象调用 static 是使用接口名点方法名调用
2.重写: default 修饰的方法是允许被重写的,执行的是实现类里重写的方法 static 修饰的方法不允许被实现类重写
3.继承: default 修饰的方法允许被子接口继承并且可以重写继承的方法 static 不可以被子接口继承
7.函数式接口
@FunctionalInterface
七.基类Object
1.Object 类的概念
Java 中Object 类是所有类的父类,也就是说Java的所有类都继承了Object,子类可以使用Object的所有方法
2.Object类的hashCode方法 (哈希值)
举例: System.out.println(Person03.hashCode() );
System.out.println(Integer.toHexString(Person03.hashCode()));
System.out.println(Person03.toString());
输出结果:802600647 //哈希值
2fd6b6c7 //哈希值变过来的16进制的字符串
com.lihaozhe.bean.Person03@2fd6b6c7
两个同样的值虽然值是一样的 但是他们仅仅是同名 位置(哈希值)并不相同
3.重写Object类的equals方法
举例:@Override
public boolean equals(Object obj) {
Person05 person04 = (Person05) obj;
if (this.age != person04.getAge()){
return false;
}else if (this.gender != person04.getGender()){
return false;
}else if (!Objects.equals(this.nickname, person04.getNickname())) {
return false;
}
else {
return true;
}
4.重写Object类的hashcode方法
举例:@Override
public int hashCode() {
int reference = 31;
return this.age * (this.gender+reference)+this.nickname.hashCode();
}
5.浅拷贝与深拷贝
浅拷贝:指的是你的类本身被拷贝,而没有拷贝类本身属性中的类
深拷贝:指的是包括类本身和属性类在内的所有类的拷贝
浅拷贝举例:public class PersonShallow implements Cloneable { //首先将类实现克隆接口
@Override
protected Object clone() throws CloneNotSupportedException { //然后重写Object中的clone方法 返回的值就是克隆后的值
return super.clone();
}
深克隆举例:public class PersonDeep implements Cloneable { //首先将类实现克隆接口
@Override
protected Object clone()throws CloneNotSupportedException{ //然后重写Object中的clone方法
PersonDeep personDeep = (PersonDeep) super.clone(); //然后将克隆值实例化
Address address = (Address) personDeep.getAddress().clone(); //然后拿到实例化里的属性类的克隆值并赋值给一个新的对象
personDeep.setAddress(address); //然后再将新的对象传送给原来的地址输入口
return personDeep; //返回克隆值