2021-03-03

1、面向过程和面向对象区别:

面向过程更注重处理事情的每一个步骤及顺序;而面向对象更关注事情有哪些参与者(对象),以及各自完成功能。以洗衣机洗衣服为例:

面向过程会将任务拆分为一系列的步骤(函数) ,如打开洗衣机---->放衣服----->加入洗衣粉----->清洗。

面向对象会拆分为人和洗衣机两个对象。其中人具有打开洗衣机、放衣服、加入洗衣粉功能;而洗衣机对象具有清洗功能。

对比:面向过程直接高效,针对事情本身;而面向对象更易于复用,便于拓展,比较繁琐。

2、面向对象三大特性:

2.1、封装

内部细节对外部调用透明(外部调用不用关心内部代码实现)。Java中两个封装的典型案例:

(1)、Java Bean的属性私有,通过getter/setter获取或赋值。在这里属性的赋值或者获取逻辑只能通过对象本身定义,不能由外部随意修改。

(2)、ORM(对象关系映射框架):引入MyBatis后,我们只用调用对应接口,不用关心连接如何建立,sql如何执行等等。

2.2、继承

继承基类(父类)共性的属性和方法,同时还可以做出自己的改变和个性化操作。Java是单继承的,注意super和this关键字。

2.3、多态

同一个行为具有多个不同表现形式或形态的能力。多态存在的三个必要条件:继承、重写、父类引用子类对象。Java中常见的两种多态使用场景:

(1)、父类类型 变量名 = new 子类类型

(2)、接口 变量名 = new 接口实现类

缺点:如果是子类或者接口实现类所独有的方法或者属性,通过上面的变量名是无法调用的,需要强制类型转换

3、JDK、JRE、JVM区别和联系:

Java Development Kit:Java开发工具

Java Runtime Environment:Java运行时环境,为要运行Java程序的人员准备的。非开发人员,仅仅想运行Java看看的人。

Java Virtual Machine:Java虚拟机。
在这里插入图片描述
JDK = JRE + Java工具(javac、jconsole等)
JRE = JVM + lib类库

4、==、equals()和hashCode():

==对比的是栈中的值。其中基本数据类型直接比较变量值;引用数据类型比较堆中内存对象地址(引用地址)

equals()方法是Object类中方法,默认也是采用==比较,但是String重写了它,用于比较两个字符串内容是否相同。

如果我们想要比较两个对象是否相等,也可以在类中重写equals()方法,一般也会重写hashCode()方法【了解过HashSet底层的都知道】。

1、练习题:Employee对象有属性name和age,只有当name和age都相同时
才认为是同一个对象。现在HashSet添加多个Employee,要让相同对象
不能进入HashSet。

public class Employee {
	private String name;
	private Integer age;

	@Override
	public boolean equals(Object obj) {
		// 因为HashSet底层会通过equals()判断两个对象是否相同,所以重写。
		if (this == obj) { // 内存地址相同
			return true;
		}
		if (obj instanceof Employee) {
			Employee employee = (Employee) obj;
			if (this.name.equals(employee.getName()) && this.age == employee.getAge()) {
				return true;
			}
			return false;
		}
		return false;// 类型都不相同,没有比较必要了
	}

	@Override
	public int hashCode() {
		// 3个不同对象的hashCode()值一定不同,转换后的索引值也不同。因此3个对象会进入不同table下标处。
		// 所以这就是为什么重写equals()方法一般都要重写hashCode()方法!!!
		return Objects.hash(name, age);
	}

	public Employee() {

	}

	public Employee(String name, Integer age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Employee [name=" + name + ", age=" + age + "]";
	}

}

public class MyHashSet {
	public static void main(String[] args) {
		HashSet<Employee> set = new HashSet<>();

		set.add(new Employee("ABC", 20));
		set.add(new Employee("ABC", 18));
		set.add(new Employee("ABC", 20));

		System.out.println("size---->" + set.size());
	}
}


2、练习题:判断下面输出true/false:
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false

Integer c = 10;
Integer d = 10;
System.out.println(c == d); // true

Integer e = new Integer(10);
Integer f = new Integer(10);
System.out.println(e == f);//false

StringBuffer buffer = new StringBuffer("ABC");
StringBuffer buffer2 = new StringBuffer("ABC");
System.out.println(buffer.equals(buffer2)); // false

原因分析:
1、/*
 *三种方式生成一个Integer对象:
 *  a、Integer a = 10;
 *  b、Integer a = new Integer(10);
 *  c、Integer a = Integer.valueOf(10);
 *  
 *  实际上a等价于c。因为a会调用Integer.valueOf()静态方法生成一个Integer对象【jdk1.5后的自动装箱】
 *  走进Integer.valueOf()源码:
 *  	public static Integer valueOf(int i) {
	        if (i >= IntegerCache.low && i <= IntegerCache.high)
	            return IntegerCache.cache[i + (-IntegerCache.low)];
	        return new Integer(i);
    	}
 这里low为-128,high为127。即只要是通过Integer.valueOf()静态方法生成的在[-128,127]之间的,都会
 存入cache数组中,而超过这个范围会new Integer(i)生成对象。
 
 结论:c和d比较地址都是cache数组中的同一个元素地址;
     a和b、e和f比较地址是两个完全不同对象的地址。
 */
 
2、StringBuffer类没有重写equals() 方法。

5、final:

5.1、final的作用:

修饰类:该类不可继承。
修饰变量:该变量一旦被赋值就不可被更改。
修饰方法:该方法不可被子类重写,允许重载。

1、final修饰普通成员变量,可以在非静态代码块、声明变量时、构造方法执行初始化。
例如:final int a = 0;//声明变量时赋值
     {
          	a = 0;//或者在非静态代码块中赋值	
     }
2、final修饰类成员变量,只能在静态代码块、声明变量时执行初始化。
例如:final static int b = 0;//声明变量时赋值
	  static{
	  		b = 0;//静态代码块赋值
	  }
3、final修饰局部变量,使用该变量前必须赋值。

5.2、为什么内部类只能访问局部final变量?

public class Test {
	private int a = 0;
	public static void main(String[] args) {
		
	}
	public void test(final int b) {	//局部变量final
		final int c = 100; //局部变量final
		//匿名内部类
		new Thread() {
			public void run() {
				System.out.println("成员变量:"+a);
				System.out.println("匿名内部类访问:"+b+"  "+c);
			};
		}.start();
	}
}

内部类和外部类是同一级别的,内部类不会随着外部类方法执行完
而被销毁。那么当外部类方法执行完,局部变量会被GC回收,但是
内部类还需要访问局部变量,怎么办???

为了解决该问题,JVM将局部变量复制一份作为内部类的成员变量,这样
即使局部变量GC回收,内部类仍可以访问。与此同时,我们必须保证
局部变量copy一份后与内部类的成员变量一致,即内部类不能修改局部
变量,因此使用final。

6、接口和抽象类区别:

1、抽象类中除了抽象方法还可以有普通成员方法;而接口只能存在抽象方法。

2、抽象类只能继承一个;而接口可以实现多个。

3、抽象类中成员变量可以是各种类型的;而接口只能是常量类型(public static final,默认的)。

4、设计目的不同:接口的设计目的是提供一种机制(功能),可以强制要求不同的类具有相同的行为。抽象类的设计目的是代码复用,它抽取各个子类共同行为作为成员方法;不同行为作为抽象方法,让各个子类独自实现。

7、Java异常体系:

1、所有异常都来自顶级父类Throwable。

2、Throwable下有两个子类Exception和Error。其中Error是程序无法处理的错误,一旦出现程序被迫停止。而Exception不会导致程序停止,又分为两个部分:RuntimeException运行时异常和CheckedException检查时异常。

3、CheckedException常常发生在程序编译过程,导致程序编译不通过。而RuntimeException常常发生在程序运行过程中,导致当前线程执行失败。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值