JAVA学习笔记 第三周

18 面向对象

18.1基本概念

18.1.1 对象

万物皆对象,对象有特征和行为,也就是属性和方法。

例如

人有特征 身高体重姓名。。

人有行为 奔跑 吃饭睡觉。。

18.1.2属性和方法

类是由属性和方法组成的

属性:一组对象共同拥有的特征。

方法:一组对象共同拥有的行为。

类是对象的抽象

对象是类的具体

18.1.3 实例变量

实例变量也叫成员变量,也叫属性

描述 实例变量 局部变量
定义位置 直接写在类中 方法中
默认值 默认值与数组相同 没有默认值
作用范围 整个类中 离当前变量最近的大括号以内
命名冲突 可以与局部变量重名,就近原则,先用局部变量,需要用实例变量要加 this.前缀 作用范围内,不能重名
存储位置 全部存储在堆中,所有才有默认值 基本数据类型存储在栈中;引用数据类型,名字在栈,值在堆中。
声明周期 随着创建对象而生效,随着对象被垃圾回收而死亡 随着方法的入栈而生效,随着方法的出栈而死亡。

18.1.4 方法重载

1:同一个类中

2:方法名相同

3:参数列表不同(参数的 个数 类型 顺序 有一个不同则为不同)。

<访问修饰符,返回值是否不同不作为方法重载的参考条件>

调用带有重载的方法时,需要根据传入的实参去找到与之匹配的方法。

好处:屏蔽使用差异,灵活,方便

18.1.5 构造方法

用于创建对象的特殊方法

无返回值

无参构造:jvm默认提供的,如果书写了有参构造而没有手动书写无参构造,无参构造会被覆盖

有参构造方法的重载:

和方法重载相同,只有一条要求,参数列表不同。

//语法:
//访问修饰符(public)+ 类名(形参列表){}
public class Student{
    String name;
    int age;
    public Student(){
        
    }
    public Student(String name,int age){
        this.name=name;
        this.age=age;
    }
}

18.1.6 this关键字

表示当前对象。

适用场景

1:可以访问属性,在和形参重名或者和局部变量重名时可以用this.实例对象

2:可以访问方法

3:可以访问构造方法

在构造方法重载时可以代替重复的部分

this()放在第一行

public Person(String name) {
		this.name = name;
	}
	
	
	public Person(String name,int age) {
		this(name);
		this.age = age;
	}
	
	public Person(String name,int age,String sex) {
		this(name,age); // 调用本类构造 必须在构造方法的第一句
		this.sex = sex;
	}

18.2 封装

解决用户不合理的给属性赋值的情况,可以用封装来实现

步骤:

1:属性私有 使用private修饰符,表示此属性只能在本类中访问而其他类中无法访问

2:方法公开,

set:每一个属性值编写set 方法输入值,命名为setName(),遵守驼峰原则可对输入值进行操作,如判断。

//setName()需要参数,但不需要返回值
public void setName(String name){
    this.name=name;
}

get:编写get方法获取值,命名getName()

//getName()不需要参数,但是需要返回值
public int getName(){
    return name;
}

简言之:一个属性设置了private修饰符,通过set输入,通过get输出活的,限制了用户的操作

封装的优点:

1:便于使用者正确使用系统,防止错误修改属性

2:降低了构建大型系统的风险

3:提高程序的可重用性

4:降低程序之间的耦合度

耦合度:

灵活性,可更改自定义增删改的地方越多,耦合度越小,越小越好。

例如乐高(低耦合度)和塑料奥特曼(高耦合度)

18.3 继承

18.3.1概念

继承是java中实现代码重用的重要手段。java中只支持单根继承,即一个类中只能有一个直接父类

子类和父类必须符合is-a关系

使用extends关键字实现继承

18.3.2 super关键字

super关键字:表示父类对象

只能用在子类的方法和构造方法中

可以访问父类访问权限允许的:

属性:super.父类属性名 属于可访问权限的属性 protected 和public 修饰的

方法:super.方法() 属于可访问权限的方法 protected 和 public 修饰的

构造方法:super()调用父类无参构造方法

		super(形参列表)调用父类有参构造方法

		1:访问父类构造方法必须在子类构造的第一句

		2:子类构造默认访问父类的无参构造方法,除非显式调用父类的有参构造方法。

也就是说,子类必须访问父类的有参或者无参构造其中一个

19 修饰符

19.1 基本修饰符

调用时提示图案

private 红色方块

默认修饰符 蓝色星星

protected 黄色菱形

public 棕色圆形

19.2 类的访问修饰符

public :公开的访问权限,本项目的任何位置都可以访问此类

默认不写:表示只能在同一个包中访问此类

19.3 类成员的访问修饰符

private:本类

默认不写:本类 ,本包

protected:本类,本包,子包

public :任何位置

20 Static 关键字

20.1修饰属性

可以用来修饰成员变量

静态变量可以直接通过类名访问

static关键字修饰的属性,在内存中只有一份,可以用于数据的共享,共享节省空间

推荐使用 类名.属性名访问,因为该变量属于整个类,不属于任何对象

是被所有当前类对象共享的数据

类的成员变量包括

类变量(静态变量)

	被static修饰的变量

	在内存中只有一个拷贝

	类内部,可在任何方法内直接访问静态变量

	其他类中,可以直接通过类名访问

实例变量

	没有被static修饰的变量

	每创建一个实例,就会为实例变量分配一次内存,实例变量在内存中有多个拷贝,互不影响

20.2 修饰方法

static修饰的方法可以通过类名访问

没有static修饰的方法只能通过new对象访问

静态方法:可直接通过类名访问

	静态方法中不能使用this和super访问所属类的实例变量和实例方法

	可直接访问类的静态变量和静态方法

实例方法:通过实例访问

	可直接访问所属类的静态变量、静态方法、实例变量和实例方法

	静态方法必须被实现

20.3修饰代码块

static{
    
}

静态代码块

当java虚拟机加载类时(只加载一次),就会执行该代码块,有多个代码块时按顺序加载

类加载的时机:

1:new对象时会加载类

2:访问类中的信息会加载类,比如访问静态变量

适用场景:

用于实现一些前置的,必须要执行的操作,并且只执行一次。比如数据初始化

20.4 static关键字实现原理

方法区:方法区是SUN公司提出的一个规范,JDK8之前称为永久代,JDK8开始称为元数据。

静态区:是指static相关的信息存储区域。

创建对象的过程:

1:当我们new对象时,JVM会先在方法区中检查,是否此类的class文件已经被加载。

如果没有被加载,则会先将class文件加载到方法区,此时静态方法的相关信息会初始化。

2:在堆中开辟空间,此时实例属性将有默认值

3:将栈中的引用指向堆中的空间

永久代/元数据:因为在方法区中初始化的数据不会随着程序的执行动态被垃圾回收,所以存储的时间比较长。另外因为方法区中的数据初始化的时机比较早,所以后来被称为元数据

20.5 关于访问

平级和平级的互相直接访问

非静态可以直接访问静态

静态不能直接访问非静态,必须先new对象

21 全限定名

当调用的两个类 同名 且来 自不同包 时

一个可以正常定义,另一个要用全限定名

com.qfedu.test6.B b1 = new com.qfedu.test6.B(); // 全限定名 指包名 +  类名

22方法重写

22.1 特点

方法重写Override的特点:

1:存在于父子类之间 父类–子类

2:方法名与父类相同 同名

3:参数列表与父类相同 形参相同

4:返回值与父类相同(或者其子类) 返回值相同

5:访问权限不能严于父类(不能窄化父类的访问权限) 大于等于父亲

根据 private 默认 protected public 从小到大顺序

6:不能抛出比父类更多的异常

7:父类静态方法可以被继承,不能被重写

22.2 @Override注解

此注解用于表示子类的方法属于重写父类的方法

写上注解后一定要按照重写规则写,否则会报错

只能用在子类的方法上

此注解不影响代码的执行结果,只用于规范方法重写

次注解可以提高代码的阅读性

22.3重写和重载的区别

重写:重写父类方法,比如object和String系统类

重载:同一个类中同名不同形参函数

23 Object类

所有类的默认父类都是Object

23.1 重写toString()类

Object和String中的toString()类

Object类中的toString方法默认返回值为:包名 + 类名 + @ + hash值

我们可以根据自己的需求进行重写,比如我们可以重写为返回值为:属性+属性值

直接打印对象名相当于访问此对象的toString方法

public String toString() {
		return "Dog[name:"+super.name+"  health:"+health+"  love:"+love+"  strain:"+strain+"]";
	}

23.2 面试题 重写equals()

==和equals()的区别?

==比较基本数据类型比较的是值

==比较引用数据类型比较的是地址

equals()本身也是比较地址,但是我们可以重写按照我们的要求来比较

String 类就的equals就是重写了Object中的equals()

equals()重写

Object和String

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }



package oop_Override_Test;

/**
 * 需求:假设现在有"两个人",名字和身份证都一样,那么这"两个人"就是同一个人,,所以使用equals比较应当为true
 * 
 * @author Administrator
 *
 */
public class Test1 {
	private String name;
	private String idCard;
	
	public Test1() {
	}

	public Test1(String name, String idCard) {
		super();
		this.name = name;
		this.idCard = idCard;
	}

	//封装
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getIdCard() {
		return idCard;  
	}

	public void setIdCard(String idCard) {
		this.idCard = idCard;
	}
	public boolean equals(Object obj) {
		if(this==obj) {
			return true;
		}
		Test1 test1=(Test1)obj;
		if(this.getName().equals(test1.getName())&& this.getIdCard().equals(test1.getIdCard())) {
			return true;
		}
		return false;
		
	}
	public static void main(String[] args) {
		Test1 t1=new Test1("王贺","411527200001303515");
		Test1 t2=new Test1("王贺","411527200001303515");
		System.out.println(t1.equals(t2));
	}

}

总结

重写object的toString()

重写equals()

23.3 重写hashCode()

hashCode属于一种杂凑算法:是指将一些杂乱的条件拼凑在一起计算出来一个值

java中的hash值是根据地址加上其他的一些条件计算出来的一个十进制的数值

为什么要重写hashCode()?

因为在一些散列数据结构中,是根据两个对象的equals比较为true,并且hashCode相同则认为是重复的对象,的这种规则来存储元素的。所以在实际开发中,通常要重写equals,也会重写hashCode。

当两个变量完全相同时,equals比较相同,但是hash值不同,不符合要求,所以要重写。

hash值是根据地址计算的,不代表地址,地址是不能变的,除非对象赋值

如:People p1=new People();

People p2=p1;//此时p1和p2的地址指向相同

public int hashCode() {
		int prime = 31; // 权重 
		int result = 1;
		result = prime * result + (this.getName() == null ? 0 : this.getName().hashCode());
		result = prime * result + (this.getIdCard() == null ? 0 : this.getIdCard().hashCode());
		return result;
	}

为什么权重选择31?

31是个很特殊的质数(素数)

任何数乘以31等于这个数左移5位,减去这个数本身

左移几位表示乘以2的几次方

右移几位表示除以2的几次方

左移是先转化为二进制,再左移,省去了转为二进制后再左移的步骤,效率较高

23.4 getClass

getClass()方法可以获取当前对象的信息 包名+类名

24 类型的属性值

当所写的属性需要一种规范,而当前的数据类型无法满足时,就要自定义数据类型对2数据进行存储。

例如,要存一个人的地址,包含省,市,区

就要自定义类Address 封装,重写toString

public class Address {
	private String province;
	private String city;

	public String getProvince() {
		return province;
	}
	public void setProvince(String province) {
		this.province = province;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	@Override
	public String toString() {
		return "Address [province=" + province + ", city=" + city + "]";
	}
}

在调用自己的类中也把自己封装,重写toString

public class People {
	private String name;
	private Address address;
	private Hobby[] hobbies;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	public Hobby[] getHobbies() {
		return hobbies;
	}
	public void setHobbies(Hobby[] hobbies) {
		this.hobbies = hobbies;
	}
	@Override
	public String toString() {
		return "People [name=" + name + ", address=" + address + ", hobbies=" + Arrays.toString(hobbies) + "]";
	}
}

在主函数中创建对象,赋值,并赋给People

People p1=new People();
		p1.setName("名字");
		Address address=new Address();
		address.setProvince("省份");
		address.setCity("市");
		p1.setAddress(address);
		
		Hobby[] hobbies=new Hobby[3];
		hobbies[0]=new Hobby();
		hobbies[1]=new Hobby();
		hobbies[2]=new Hobby();
		
		hobbies[0].setHobbyType("体育");
		hobbies[1].setHobbyType("电影");
		hobbies[2].setHobbyType("动漫");
		
		hobbies[0].setHobbyName("a");
		hobbies[1].setHobbyName("b");
		hobbies[2].setHobbyName("c");
		
		p1.setHobbies(hobbies);
		System.out.println(p1);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值