Java基础要点笔记2面向对象(尚硅谷)

写在前面:Java基础系列文章

Java基础要点笔记1(尚硅谷)
Java基础要点笔记2面向对象(尚硅谷)
Java编程之异常处理
Java编程之多线程
Java编程之常用类
Java编程之枚举类&注解
Java编程之Java集合
Java编程之泛型
Java编程之IO流
Java编程之网络编程
Java编程之反射机制
Java编程之Java8&9&10&11新特性
十大排序算法
关于设计模式

Java基础

  • 写在前面:Java基础系列文章
  • Java面向对象编程(尚硅谷)
    • 1. Java类及类成员(属性、方法、构造器、代码块、内部类)
      • 1.1 概述
      • 1.2 对象的内存解析(重点)
      • 1.3 属性与局部变量
        • 1.3.1 在类中声明的位置不同
        • 1.3.2 关于权限修饰符的不同
        • 1.3.3 默认初始化值的情况
        • 1.3.4 在内存中加载的位置(重点)
      • 1.4 类中方法的声明和使用
      • 1.5 匿名对象的使用
      • 1.6 再谈方法
        • 1.6.1 方法的重载overload
        • 1.6.2 可变形参的方法
        • 1.6.3 方法参数的值传递机制★
        • 1.6.4 递归方法recursion
      • 1.7 类的成员之四:代码块(初始化块)
      • 1.8 类的成员之四:内部类
    • 2. 面向对象的三大特征
      • 2.1封装性
        • 2.1.1 类的成员之三(构造器也称构造方法)
      • 2.2 继承性
        • 2.2.1 Object类
        • 2.2.2 方法的重写(override / overwrite)
        • 2.2.3 子类对象实例化全过程
      • 2.3 多态性
        • 2.3.1 理解多态性
        • 2.3.2 何为多态性
        • 2.3.3 多态的使用:虚拟方法的调用
        • 2.3.4 多态的使用前提
        • 2.3.5 instanceof关键字
    • 3. 其他关键字 (知道在哪用,怎么用,用来做什么)
      • 3.1 this关键字
      • 3.2 package关键字
      • 3.3 import关键字
      • 3.4 super关键字
      • 3.5 static关键字
      • 3.6 final关键字
    • 4. MVC设计模式
    • 5. Object类的使用
    • 6. 包装类Wrapper的使用
      • 6.1 八种包装类
      • 6.2 关于包装类使用的面试题
    • 7. Java中的JUnit单元测试
    • 8. 抽象类和抽象方法(重点)
    • 8. 接口(重点)
  • 总结

Java面向对象编程(尚硅谷)

1. Java类及类成员(属性、方法、构造器、代码块、内部类)

1.1 概述

  类就是一个抽象的概念,对象就是一个具体的实例,类成员有类属性和类方法,通过“对象.属性”或“对象.方法”调用对象的结构

  注:Person p3 = p1 ; // 将p1变量保存的对象地址赋给p3,导致p1和p3指向堆空间中的同一个对象实体,一个属性的修改,另一个也会进行相应的修改

1.2 对象的内存解析(重点)

  主要介绍运行时数据区的三个部分:
Java基础要点笔记2面向对象(尚硅谷)_第1张图片
堆Heap: 此内存区域的唯一目的就是存放对象实例,所有对象实例以及数组都要在堆上分配;

虚拟机栈Stack: 即通常所说的栈,用于存放局部变量等,局部变量表存放了编译器可知长度的各种基本数据类型、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址),方法执行完,自动释放;

方法区Method Area: 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
Java基础要点笔记2面向对象(尚硅谷)_第2张图片
为了加深理解,再附一张对象数组的内存解析图:
Java基础要点笔记2面向对象(尚硅谷)_第3张图片
引用类型的变量,只可能存储两类值:null 或 地址值(含变量的类型)
比如Phone的对象p,打印出来的值为
对象地址
  需要注意的是,编译完源程序以后,生成一个或多个字节码文件,我们使用JVM中的类加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载解析(是执行java xxx.exe的时候做的事情)

1.3 属性与局部变量

相同点在于定义的格式相同;先声明、后使用;变量都有其对应的作用域。
下面重点介绍一下不同点:

1.3.1 在类中声明的位置不同

  属性:直接定义在类中;

  局部变量:声明在方法内、方法形参、代码内、构造器形参、构造器内部的变量;

1.3.2 关于权限修饰符的不同

  属性:可以在声明属性时,指明其权限,使用权限修饰符:peivate、public、protected

  局部变量:不可以使用权限修饰符

1.3.3 默认初始化值的情况

  属性:根据其类型,都有默认初始化值
  整型(byte、short、int、long) 0
  浮点型(float、double) 0.0
  字符型(char) 0或’\u0000’
  布尔型(boolean) false
  引用数据类型(类、数组、接口):null

  局部变量:没有默认初始值,调用局部变量之前一定要显示赋值,特别的,形参在调用时赋值即可。

1.3.4 在内存中加载的位置(重点)

  属性:加载到堆内存中(非static)

  局部变量:加载到栈空间

  注:解释一下堆共享和栈共享,参见https://blog.csdn.net/fox_bert/article/details/88367002,讲的挺清楚

  栈是数据共享,堆是线程共享(我理解的数据共享就是在栈中有1个3,然后多个int类型的变量指向它。而对于new出来的对象,比如String,每次new都会在堆中有新的地址,哪怕字符串的内容是一样的。)

  数据共享的有栈、常量池、寄存器、PC
  线程共享的有堆、全局变量、静态变量、方法区

1.4 类中方法的声明和使用

  ctrl+shift+t 可以搜索类文件,进到类文件后 ctrl+o 可以搜索方法

  权限修饰符 返回值类型 方法名(形参列表){
    // 方法体
  }
  注:static、final、abstract也可以修饰方法,后面再讲

如何理解“万事万物皆对象”?
在Java语言中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构;当涉及到与前端、数据库在java层面交互时,都体现为类、对象。

1.5 匿名对象的使用

  1. 理解:在创建对象的时候,没有显式的赋给一个变量名,即为匿名对象
  2. 特征:匿名对象只能调用一次

1.6 再谈方法

1.6.1 方法的重载overload

定义: 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。(与返回类型无关)

总结: “两同一不同”:同一个类、相同方法名;参数列表不同

1.6.2 可变形参的方法

jdk1.5提供了Varargs机制,允许直接定义和多个实参相匹配的形参。

  1. 格式:数据类型 … 变量名
  2. 特点:当调用可变个数形参的方法时,传入的参数个数可以是:0个、1个、2个…
  3. 可变个数形参的方法与本类中方法同名,形参不同的方法之间构成重载(如果有参数完全匹配的方法,那么会调用完全匹配的方法)
  4. 可变个数形参的方法与本类中方法同名,形参类型也相同数组之间不构成重载。换句话说,二者不能共存。
    publiv void show(String … strs){
    }
    public void show(String[] strs){
    }
    上面两个方法是一样的,遍历的时候,也是一样的,都是当做数组
  5. 可变个数形参在方法的形参中,必须声明在末尾
  6. 可变个数形参在方法的形参中,最多只能声明一个可变形参

这种可变形参的方法可以用在sql语句的where字句那,因为有时候不知道会匹配几个参数。
Java基础要点笔记2面向对象(尚硅谷)_第4张图片
补充:对于可以自动类型转换的,可以在传参时传入,比如现在实参为int型,但是方法中没有形参为int型,有形参是double,那么也可以传进去。(多个参数也是一样,能自动类型转换,表示能够匹配,我在eclipse中试着是可以的)

1.6.3 方法参数的值传递机制★

关于变量赋值:

  1. 如果变量是基本数据类型,此时赋值的是变量所保存的数据值;
  2. 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值;

值传递机制:

  1. 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值
  2. 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值
    Java基础要点笔记2面向对象(尚硅谷)_第5张图片
    下面从内存角度理解下:
    Java基础要点笔记2面向对象(尚硅谷)_第6张图片
    Java基础要点笔记2面向对象(尚硅谷)_第7张图片
    拓展:
    第一道题目:
public class Test {
     
	public static void main(String[] args) {
     
		int a = 10 ;
		int b = 10 ;
		method(a,b) ;
		System.out.println("a="+a);
		System.out.println("b="+b);
	}
}

在不改变原本题目的前提下,如何写这个函数才能在main函数中输出a=100,b=200?
方法一:在method方法中输出,之后System.exit(0) ;
方法二:重置打印流,重写println

第二道题目:微软
定义一个int型的数组:int[] arr = new int[]{12,3,4,5,654,765,54,34,645,32} ;让数组的每个位置上的值除以首位置的元素,得到结果,作为该位置上的数值,遍历新的数组。
解法:倒着遍历

第三道题目:
int[] arr = new int[]{1,2,3} ;
System.out.println(arr) ; //地址值
char[] arr1 = new char[]{‘a’,‘b’,‘c’} ;
System.out.println(arr1) ; //abc
分析:这是跟println方法有关,传入的数组参数都是用Object来接收,但是对于char数组,是直接用char数组来接收的,会打印数组中的所有内容。

1.6.4 递归方法recursion

一个方法体内调用它自身。
例题:计算1-100之间所有自然数的和

public int getSum(int n){
     
	if(n==1){
     
		return 1 ;
	}else{
     
		return n + getSum(n-1) ;
	}
}

1.7 类的成员之四:代码块(初始化块)

Java基础要点笔记2面向对象(尚硅谷)_第8张图片
这里需要注意的是: 代码块先于构造器执行
比如现在Leaf的父类是Mid,Mid的父类是Root,每个类中有静态代码块、非静态代码块,若干构造函数,现在new一个静态Leaf,它们的执行顺序为:
Java基础要点笔记2面向对象(尚硅谷)_第9张图片

main方法除了是程序的入口之外,也是一个普通的静态方法,也是在执行main方法之前,如果main所在的类中有静态代码块,也会先于main方法

1.8 类的成员之四:内部类

Java基础要点笔记2面向对象(尚硅谷)_第10张图片
成员内部类和局部内部类,在编译以后,都会生成字节码文件。

格式:

成员内部类:外部类$内部类.class

局部内部类:外部类$数字 内部类名.class

规定:局部内部类的方法中,如果调用局部内部类所声明的方法中的局部变量,则要求该变量声明为final。jdk7及以前的版本,要求显示声明为final,但是Jdk1.8之后可以省略final的声明(我理解如果被局部内部类调用了,那么在其他地方也不能修改了)
局部内部类不能有访问控制修饰符,且不能用static修饰,但是可以是abstract和final的

需要知道三个问题

  1. 如何实例化成员内部类的对象?
// 创建静态成员内部类实例
Person.Dog dog = new Person.Dog() ;
// 创建非静态成员内部类实例
Person p = new Person() ;
Person.Bird bird = p.new Bird() ;
  1. 如何在成员内部类中区分调用外部类的结构?
// 内部类中的方法
public void display(String name) {
     
	System.out.println(name) ;  // 方法形参
	System.out.println(this.name) ;   // 内部类的属性
	System.out.println(Person.this.name) ;   // 外部类的属性
}
  1. 开发中局部内部类的使用?
    Java基础要点笔记2面向对象(尚硅谷)_第11张图片
    内部类总结:
    Java基础要点笔记2面向对象(尚硅谷)_第12张图片

2. 面向对象的三大特征

2.1封装性

  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
  • 低耦合:仅对外暴露少量的方法用于使用
    面试回答:隐藏对象内部的复杂性,只对外公开简单的接口,便于外界调用,从而提高系统的可扩展性、可维护性。

问题的引入:
  当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值,这里,赋值操作要受属性的数据和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件,这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件大的添加。同时为了避免用户再使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为私有的private—>此时针对属性就体现了封装性。

封装性的体现
  我们将类的属性xxx私有化private,同时,提供公共的public方法来获取getXxx和设置setXxxx

拓展:封装性的其他体现:比如 不对外暴露的私有方法、单例模式、如果不希望类在包外被调用,可以将类设置为缺省(类只能是public或缺省)等等。

封装性的体现,需要权限修饰符配合

  1. Java规定的四种权限修饰符:private、缺省、protected、public,置于类成员定义前,用来限定对象对该类成员的访问权限。
    Java基础要点笔记2面向对象(尚硅谷)_第13张图片
  2. 四种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类 (无代码块)
    修饰类的话,只能使用:缺省、public

总结:Java提供了四种权限修饰符来修饰类及类的内部结构,体现了其在被调用时的可见性大小。

2.1.1 类的成员之三(构造器也称构造方法)

构造器的作用:

  1. 创建对象
  2. 初始化对象的信息

说明:

  1. 如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器(默认构造器的权限和类权限相同)
  2. 定义构造器的格式:权限修饰符 类名(形参列表){ }
  3. 一个类中定义的多个构造器,彼此之间构成重载
  4. 一旦我们显示的定义了类中的构造器之后,系统就不再提供默认的空参构造器
  5. 一个类中,至少会有一个构造器

总结:属性赋值的先后顺序

① 默认初始化
② 显示初始化/③ 在代码块中赋值 (这两个看写的先后顺序)
④ 构造器中初始化
⑤ 通过“对象.方法” 或 “对象.属性”的方式,赋值

拓展知识:JavaBean

① JavaBean是一种Java语言写成的可重用组件
②所谓JavaBean,符合如下标准的java类:

类是公共的
有一个无参的公共的构造器
有属性,且有对应的get、set方法


Java基础要点笔记2面向对象(尚硅谷)_第14张图片
拓展知识:UML类图
Java基础要点笔记2面向对象(尚硅谷)_第15张图片

2.2 继承性

1. 继承性的好处

① 减少了代码的冗余,提高了代码的复用性
② 便于功能的扩展
③ 为之后的多态性的使用,提供了前提

2. 继承性的格式:class A extends B{ }

A:子类、派生类、subclass
B:父类、超类、基类、superclass

① 体现:一旦子类A继承父类B之后,子类A中就获取了父类B中声明的所有的属性和方法;
特别的,父类中声明为private的属性或方法,子类中继承之后,仍然认为获取了父类中的私有结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已。
② 子类继承父类之后,还可以声明自己特有的属性或方法:实现功能的拓展

3. Java中关于继承性的规定

① 一个类可以被多个子类继承
② Java中类的单继承:一个类只能有一个父类
③ 子父类是相对的概念
④ 子类直接继承的父类称为直接父类,间接继承的父类称为间接父类
⑤ 子类继承父类之后,就获取了父类以及所有间接父类中声明的属性和方法
Java基础要点笔记2面向对象(尚硅谷)_第16张图片
4. 类图

子类箭头指向父类
Java基础要点笔记2面向对象(尚硅谷)_第17张图片

2.2.1 Object类

eclipse中快捷键ctrl+t可以看到类的继承情况

如果我们没有显示的声明一个类的父类的话,则此类继承于java.lang.Object类。也就是说所有java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类。

所以,所有的java类具有java.lang.Object类声明的功能,后面会对Object进行讲解。

2.2.2 方法的重写(override / overwrite)

1. 重写: 子类继承父类之后,可以对父类中同名同参数的方法,进行覆盖操作
2. 应用: 重写之后,当创建子类对象之后,通过子类对象调用父类中同名同参数的方法时,实际执行的是子类重写父类的方法。

Person父类:

package com.atguigu.contact;

public class Person {
     
	String name ;
	int age ;
	
	public Person(){
     
	
	}
	
	public Person(String name, int age){
     
		this.name = name ;
		this.age = age ;
	}
	
	public void eat(){
     
		System.out.println("Person: 吃饭");
	}
	
	public void walk(int distance){
     
		System.out.println("Person走路:距离是" + distance + "公里");
		// 难点:因为这里父类中的show方法是私有的,所以子类中不能算是重写,所以如果子类对象调用walk方法,这里会调用父类的show方法
		System.out.println("下面为调用父类中的show方法");
		show() ;
		// 难点:因为子类中重写eat方法,所以如果是子类对象调用walk方法,这里,会调用子类的eat方法
		System.out.println("下面为调用子类中的eat方法");
		eat() ;
	}
	
	private void show(){
     
		System.out.println("Person:调用show方法");
	}
}

Student子类:

package com.atguigu.contact;

public class Student extends Person{
     
	String major ;
	
	public Student(){
     
		
	}
	
	public Student(String major){
     
		this.major = major ;
	}
	
	public void study(){
     
		System.out.println("Student:学习。专业是:major");
	}
	
	// 对父类中的eat进行了重写
	public void eat(){
     
		System.out.println("Student:多吃有营养的食物");
	}
}

测试类

package com.atguigu.contact;

public class PersonTest {
     
	public static void main(String[] args) {
     
		Student s = new Student("计算机科学与技术") ;
		// 子类调用的是子类重写的方法
		s.eat() ;
		System.out.println();
		// 子类没有该方法,调用父类的方法
		System.out.println("子类对象调用walk方法,walk方法中调用了show方法和eat方法,其中show方法没有被子类重写,eat方法有被重写:");
		s.walk(10) ;
		System.out.println();
		// 不是重写的方法,子类自己的方法
		s.study() ;
		
		
		Person p = new Person() ;
		// 父类对象调用肯定是调用自己的方法
		p.eat() ;
	}
}

输出结果:

Student:多吃有营养的食物

子类对象调用walk方法,walk方法中调用了show方法和eat方法,其中show方法没有被子类重写,eat方法有被重写:
Person走路:距离是10公里
下面为调用父类中的show方法
Person:调用show方法
下面为调用子类中的eat方法
Student:多吃有营养的食物

Student:学习。专业是:major
Person: 吃饭

3. 重写的规定:

方法的声明方式:

权限修饰符  返回值类型  方法名(形参列表) throws  异常的类型{
     
// 方法体
}

约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法

① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符

特殊情况:子类不能重写父类中声明为private权限的方法

③ 返回值类型:
Ⅰ 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
Ⅱ 父类被重写的方法返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
Ⅲ 父类被重写的方法的返回值类型是基本数据类型(比如double),则子类重写的方法的返回值类型必须是相同的基本数据类型

package com.atguigu.p2.ui;

public class CustomerView {
     
	public void main(String[] args) {
     
		a() ;
	}
	
	public int a(){
     
		System.out.println("dfsjt");
		return 1 ;
	}
}
 
package com.atguigu.p2.ui;

public class Test extends CustomerView {
     
	public static void main(String[] args) {
     
		Test test = new Test() ;
		test.a() ;
	}
	
	public double a(){
           //这里要注意的是如果子类中有跟父类中相同方法名和形参列表的方法,那么java会自动认为你要重写该方法,如果返回值类型跟父类中的不一样,那么会报错
		System.out.println("dfs");
		return 1.0 ;
	}
	
}

Java基础要点笔记2面向对象(尚硅谷)_第18张图片
④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲)

注意:子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)

4. 关于重写:

  1. 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。
  2. 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边。
class Base {
     
	int count = 10 ;
	public void display() {
     
		System.out.println(this.count) ;
	} 
}

class Sub extends Base {
     
	int count = 20 ;
	public void display() {
     
		System.out.println(this.count) ;
	}
}

public class FieldMethodTest {
     
	pubilc static void main(String[] args) {
     
		Sub s = new Sub() ;
		System.out.println(s.count) ;  // 20
		s.display() ;   // 20
		Base b = s ;
		//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
		System.out.println(b==s) ;   // true
		System.out.println(b.count) ;  // 10
		b.display() ;  // 20
	}
}

2.2.3 子类对象实例化全过程

从结果上来看:(继承性)

  1. 子类继承父类以后,就获取了父类中声明的属性或方法
  2. 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性

从过程上看:
  当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器 ,进而调用父类的父类的构造器,直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类的结构,子列对象才可以考虑进行调用。
Java基础要点笔记2面向对象(尚硅谷)_第19张图片

注意:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

2.3 多态性

2.3.1 理解多态性

  可以理解为一个事物的多种形态

2.3.2 何为多态性

  对象的多态性:父类的引用指向子类的对象(或者说子类的对象赋给父类的引用)

对象的多态性只适用于方法,不适用于属性(编译和运行都看左边)

TODO问题:子类中包含自己及父类所有的方法吗?这些方法放在哪里了?是方法区吗?

2.3.3 多态的使用:虚拟方法的调用

  有对象的多态性以后,我们在编译期,只能调用父类声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

  总结: 编译看左边,运行看右边

  另外, 多态是运行时行为 ,举例的话可以说equals()方法,传进去的值是用Object来接收的,如果没有多态的话,需要写很多类型的形参的equals方法。

解释一下虚拟方法:
Java基础要点笔记2面向对象(尚硅谷)_第20张图片

重载不是多态,重写是多态。
Java基础要点笔记2面向对象(尚硅谷)_第21张图片
练习:
Java基础要点笔记2面向对象(尚硅谷)_第22张图片
第一个base.add(1,2,3) ; 调用的是Sub1中的第一个add方法,也就是这个int… arr和int[] arr算是重写,但是和int a,int b,int c不算是重写

第二个s.add(1,2,3) ; 调用的是Sub1中的第二个add方法。(因为参数是明确的)

2.3.4 多态的使用前提

  1. 要有类的继承关系;
  2. 要有方法的重写,否则没有必要转型

2.3.5 instanceof关键字

  有了对象的多态之后,内存中实际上是加载了子类特有的属性和方法,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

那么如何才能调用子类特有的属性和方法?

  1. 向下转型:使用强制类型转换符,但是很有可能出现ClassCastException的异常, 可以使用instanceof来进行类型的判断:
    a instanceof A:判断对象a是否是类A的实例。如果是,返回true; 如果不是返回false。

要求a所属的类与类A必须是子类和父类的关系,否则编译错误

// Man继承自Person
Person p = new Man() ;
if(p instance Man){
         // true
	Man m = (Man)p ;
}

Person p2 = new Person() ;
if(p2 instanceof Man) {
        // false  个人认为向下转型前,必须向上转型
	System.out.println("true2");
}

Man m = new Man();
if(m instanceof Person) {
        // true
	System.out.println("true3");  
}
  1. 向上转型就是对象的多态性

3. 其他关键字 (知道在哪用,怎么用,用来做什么)

3.1 this关键字

  1. this关键字的使用:可以用来修饰属性、方法,调用构造器;
  2. this修饰属性和方法理解为:当前对象或当前正在创建的对象;
  3. this调用构造器
    ① 在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中指定的其他构造器;
    ② 不能自己调自己,不能互相调
    ③ 规定:“this(形参列表)” 必须声明在当前构造器的首行,也就是构造器内部最多只能声明一个this(形参列表)
    Java基础要点笔记2面向对象(尚硅谷)_第23张图片

3.2 package关键字

  1. 为了更好的实现项目中类的管理,提供了包的概念;
  2. 使用package声明类或接口所属的包,声明在源文件的首行;
  3. 包名,属于标识符,遵循标识符的命名规则;
  4. 每"."一次,就代表一层文件目录

补充:同一包下,不能命名同名的接口、类; 不同包下,能够命名同名的接口、类。

3.3 import关键字

Java基础要点笔记2面向对象(尚硅谷)_第24张图片
例子:
import static java.lang.Math.* ;

之后可以直接使用Math中的属性或方法:int t = sqrt(100) ;

3.4 super关键字

Java基础要点笔记2面向对象(尚硅谷)_第25张图片
在这里插入图片描述

注意: 父类 仅仅声明了有参构造函数,没有自己声明无参构造函数,则子类必须重写 父类构造函数(也就是super调用)。父类 有无参构造函数,则子类不必重写父类构造函数。

关于this和super只能选一个:无论哪个构造器创建子类对象,需要保证先初始化父类,目的是当子类继承父类后,“继承”父类中所有的属性和方法,因此子类有必要知道父类如何为对象进行初始化。

3.5 static关键字

Java基础要点笔记2面向对象(尚硅谷)_第26张图片

  1. static关键字的使用
  • static:静态的
  • static可以用来修饰:属性、方法、代码块、内部类(注意没有构造器)
  • 使用static修饰属性:静态变量(类变量)

① 属性:按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)

实例变量: 我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量: 我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量,是修改过了的。

② static修饰属性的其他说明:

1.静态变量随着类的加载而加载,可以通过“类.静态变量”的方式进行调用。
2.静态变量的加载要早于对象的创建;
3.由于类只会加载一次,则静态变量在内存中也会只存在一份:存在方法区的静态域中;
4.类不能调用实例变量,可以调用类变量,对象都可以调用;

③ 静态属性举例:System.out、Math.PI ;

  • 使用static修饰方法:静态方法

① 随着类的加载而加载,能够通过“类.静态方法”来进行调用;
② 类不能调用非静态方法,可以调用静态方法,对象都可以调用;
③ 静态方法中只能调用静态方法或属性,非静态方法都可以(主要是由于生命周期)

  • 在静态方法中不能使用this,super关键字,因为它不存在当前对象,它是属于类的(静态属性前面省略的不是this. 而是类.)(但是在非静态方法中,用this.调用静态属性也不会出错)

  • 在开发中,如何确定一个属性是否要声明为static?

1.属性可以被多个对象所共享的,不会随着对象的不同而不同;
2.类中常量也常常声明为static

  • 在开发中,如何确定一个方法是否要声明为static?

1.操作静态属性的方法,通常设置为static的;
2.工具类中的方法,习惯声明为static的,比如Math、Arrays、Collections

  • static应用
    ① 比如想让id自增,可以:
private int id ;
private static int total ;   // 记录创建对象的总个数
private static int init = 1 ;    // static声明的属性被所有对象共享
public Circle(){
     
	id = init++ ;
}

3.6 final关键字

Java基础要点笔记2面向对象(尚硅谷)_第27张图片

final 可以声明成员变量、局部变量、方法、类
static可以修饰代码块、成员变量、方法,不可以修饰类,但是可以修饰内部类
static有一个应用是单例模式,面试常考:关于设计模式

练习两道简答面试题:

  1. 下面这道题:++x是不可以的,但是x+1是可以的
    Java基础要点笔记2面向对象(尚硅谷)_第28张图片
    2.下面这道题,new是不可以的,但是o.i++是可以的,只要这个对象不变就行了
    Java基础要点笔记2面向对象(尚硅谷)_第29张图片

4. MVC设计模式

MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层、控制器层、数据库模型层。这种程序输入输出、数据处理,以及数据的战术分离开来的设计模式使程序结构变的灵活清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。
Java基础要点笔记2面向对象(尚硅谷)_第30张图片

5. Object类的使用

Java基础要点笔记2面向对象(尚硅谷)_第31张图片
补充一点点jvm知识:
Java基础要点笔记2面向对象(尚硅谷)_第32张图片
这里可能会涉及一些面试题:比如fianl、finally、finalize的区别,==和equals的区别
Java基础要点笔记2面向对象(尚硅谷)_第33张图片
补充: ==符号使用时,必须保证符号左右两边的变量类型一致。

举例:

int i = 10 ;
double j = 10.0 ;
System.out.println(i==j) ;  // true

一、equals() 方法的使用:
① 是一个方法,而非运算符
② 只能适用于引用数据类型
③ Object类中的equals()方法:

public boolean equals(Object obj){
     
	return (this==obj) ;
}
// 说明:Object中定义的equals()方法和==的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。

④ 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写之后,比较的不是两个引用
的地址是否相同,而是比较两个对象的“实体内容”是否相同。
⑤ 通常情况下,我们自定义的类如果使用equlas()的话,也通常是比较两个对象的实体内容是否相同,那么就需要对Object类中的equals()进行重写。(Eclipse中可以自动生成equals方法)
自己简单些的话,一般就是:

public boolean equals(Object obj) {
     
	if(obj == this){
     
		return true ;
	}
	if(obj instanceof User){
     
		User u = (User)obj ;
		return this.age == u.age && this.name.equals(u.name) ;
	}
	return false ;
}

Java基础要点笔记2面向对象(尚硅谷)_第34张图片
练习:

  1. 补充一些关于String的equals比较的小知识,后面还会详细讲:
    比如现在有一个Order类,
Order order1 = new Order(1001, "AA") ;
Order order2 = new Order(1001, "AA") ;
Order order3 = new Order(1001, new String("AA")) ;

//在equals中是这样写的:
return this.orderId == order.orderId && this.orderName == order.orderName ;

system.out.println(order1==order2) ;  // true
system.out.println(order1==order3) ;  // false

String s1 = "BB" ;
String s2 = "BB" ;
System.out.println(s1==s2) ;  // true

// 这是因为常量池

所以平时如果比较的是基本数据类型,就用==;如果是引用数据类型,就用equals

  1. 比较两个圆的半径是否相等
public boolean equals(Object obj) {
     
	if(this==obj){
     
		return true ;
	}
	if(obj instanceof Circle) {
     
		Circle c = (Circle)obj ;
		return this.radius==c.radius ;
	}
	return false ;
}

二、toString() 方法的使用

  1. 当我们输出一个对象的引用时,实际上调用当前对象的toString()
  2. Object类中的toString()的定义:
public String toString() {
     
	return getClass().getName() + "@" + Integer.toHexString(hashCode) ;
}
  1. 像String、Date、File、包装类等都重写了Object类中的toString()方法,使得在调用对象的toString()方法时,返回“实体内容”信息。
  2. 自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”。

6. 包装类Wrapper的使用

6.1 八种包装类

java提供了8中基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征;
Java基础要点笔记2面向对象(尚硅谷)_第35张图片
基本数据类型、包装类与String类间的转换

① 基本数据类型–>包装类: 调用包装类的构造器

public class WrapperTest {
     
	public void test1() {
     
		int num1 = 10 ;
		Integer in1 = new Integer(num1) ;
		System.out.println(in1.toString()) ;  // 10
		
		Integer in2 = new Integer("123") ;   // 这里的String必须是数字组合
		System.out.println(in2.toString()) ;  // 123
		
		// 报异常
		// Integer in3 = new Integer("123abc") ;
		// System.out.println(in3.toString()) ;

		Float f1 = new Float(12.3f) ;
		Float f2 = new Float("12.3") ;

		// Boolea有些特殊,注意下
		Boolean b1 = new Boolean(true) ;   // true
		Boolean b2 = new Boolean("TrUe") ;   // true
		Boolean b3 = new Boolean("true123") ;  // false
		// Boolean构造器的实现,只要传进去的是true就行,不区分大小写
		
		Oerder order = new Order() ;
		System.out.println(order.isMale) ;   // false  
		System.out.println(order.isFemale) ;   // null
	}
}

class Order {
     
	boolean isMale ;
	Boolean isFemale ;
}

② 包装类–>基本数据类型: 调用包装类的xxxValue()

int i1 = in1.intValue() ;
float f1 = fl1.floatValue() ;

JDK5.0性特性:自动装箱与自动拆箱

③ 基本数据类型、包装类–>String类型: 调用String重载的valueOf()方法

// 方法1:连接运算
String str1 = num1 + "" ;
// 方法2:调用String的valueOf(Xxx xxx)
float f1 = 12.3f ;
String str2 = String.valueOf(f1) ;  // "12.3"
// 别的类型也一样的方法 

③ String类型–>基本数据类型、包装类: 调用包装类的parseXxx(String s)

String str1 = "123" ;
// 错误情况:
// int num1 = (int)str1 ;  // 不可以
// Integer in1 = (Integer)str1 ;  // 两个没有继承关系的类,不能强转

int num2 = Integer.parseInt(str1) ; // 如果不是纯数字会出错,NumberFormatException

String str2 = "true" ;    // 如果不是true(不分大小写,那么就是false),比如truexx
boolean b1 = Boolean.parseBoolean(str2) ; 

6.2 关于包装类使用的面试题

public void test1(){
     
	Object o1 = true ? new Integer(1) : new Double(2.0) ;
	System.out.println(o1) ;   // 1.0  因为三目运算符在编译的时候就要求后面两个的类型是相同的
}

public void test2 {
     
	Object o2 ;
	if(true){
     
		o2 = new Integer(1) ;
	}else{
     
		o2 = new Double(2.0) ;
	}
	System.out.println(o2) ;  // 1   这么写的话,对类型没有要求
}

Integer类的缓存机制
Java基础要点笔记2面向对象(尚硅谷)_第36张图片

7. Java中的JUnit单元测试

Java基础要点笔记2面向对象(尚硅谷)_第37张图片

public class JUnitTest {
     
	int num = 10 ;

	@Test
	public void testEquals() {
     
		String s1 = "123" ;
		String s2 = "456" ;
		System.out.println(s1.equals(s2)) ;
	}
}

8. 抽象类和抽象方法(重点)

Java基础要点笔记2面向对象(尚硅谷)_第38张图片
Java基础要点笔记2面向对象(尚硅谷)_第39张图片
在这里插入图片描述

静态方法不能被重写,abstract修饰的方法没有方法体,类直接调没有意义。

创建抽象类的匿名子类的匿名对象:Person是一个抽象类

method(new Person(){
     
	@Override
	public void eat(){
     
		// .....
	}
});

Java基础要点笔记2面向对象(尚硅谷)_第40张图片

模板方法,把基本操作组合到一起,子类一般不能重写。
模板方法中会调用重写的方法,所以不用手动去调用重写方法,直接调用模板方法就可以。
Java基础要点笔记2面向对象(尚硅谷)_第41张图片

8. 接口(重点)

一方面,Java不支持多重继承,但是有了接口就可以得到多重继承的效果;另一方面有时必须从几个类中抽取出一些公共的行为特征,但是它们之间有没有is-a的关系,就需要用到接口。
Java基础要点笔记2面向对象(尚硅谷)_第42张图片
8.接口的具体使用,体现多态性
因为接口不能实例化对象,所以在使用时只能使用它的子类,这就体现了多态性

9.接口,实际上可以看作是一种规范

10.和抽象方法一样,也能够创建匿名实现类

面试题:抽象类和接口有哪些异同?

同:不能实例化,都可以被继承;
异:抽象类有构造器,接口没有;抽象类是单继承,接口是多继承;

接口的应用

  1. 代理模式(Proxy)—>静态代理
    代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
public class NetWorkTest{
     
	public static void main(String[] args){
     
		Server server = new Server() ;
		//server.browse() ;
		ProxyServer proxyserver = new ProxyServer(server) ;
		
		proxyServer.brower() ;
	}
}

interface Network{
     
	public void browse() ;
}

// 被代理类
class Server implements Network{
     
	@Override
	public void browse(){
     
		System.out.println("真实的服务器访问网络!") ;
	}
}

// 代理类
class ProxyServer implements Network{
     
	private Network work ;
	public ProxyServer(Network work){
     
		this.work = work ;
	}
	public void check(){
     
		System.out.println("联网之前的检查工作") ;
	}
	@Override
	public void browse(){
     
		check() ;
		work.browse() ;
	}
}

Java基础要点笔记2面向对象(尚硅谷)_第43张图片

  1. 工厂模式
    工厂模式:实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
    体现了六大原则中的三个原则:
    开放封闭原则:一个软件的实体应当对扩展开放,对修改关闭;
    依赖倒转原则:针对接口编程,不要针对实现编程,解耦调用和被调用者;
    迪米特法则:要求尽量封装,尽量独立,尽量使用低级别的访问修饰符,两个类直接联系尽量少,通过第三方来做。

两道面试题

  1. 继承类和实现接口中的属性名相同,直接输出会报错。
    Java基础要点笔记2面向对象(尚硅谷)_第44张图片
  2. 这道题的关键不是在于继承的两个接口里面都有play()方法,但是实现类中只重写了一次,这是没有问题的,问题在于ball是一个常量,不能在实现类中更改!
    接口中的属性的public static final和方法public abstract都可以省略不写
    Java基础要点笔记2面向对象(尚硅谷)_第45张图片

Java8中关于接口的改进

Java中,可以为接口添加静态方法和默认方法。

静态方法:使用static关键字修饰。只能通过接口直接调用静态方法,并执行其方法体。
默认方法:默认方法使用default关键字修饰。可以通过实现类对象来调用。

比如Collections类中定义了大量的操作Collection接口的静态方法,那么之后可以慢慢的把这些方法都放在Collection中,使之具有工具类的功能。

public interface CompareA {
     
	// 静态方法
	public static void method1() {
     
		System.out.println("CompareA:北京") ;
	}
	// 默认方法
	public default void method2() {
     
		System.out.println("CompareA:上海") ;
	}
	// 默认方法的public可以省略,但权限还是public
	default void method3() {
     
		System.out.println("CompareA:上海") ;
	}
}

public class SubClassTest {
     
	SubClass s = new SubClass() ;
	// 不可以
	// s.method1() ;
	// 不可以
	// SubClass.method1() ;
	// 知识点1:接口中定义的静态方法,只能通过接口来调用
	CompareA.method1() ;
	// 知识点2:通过实现类的对象,可以调用接口中的默认方法
	// 如果实现类重写了接口中默认的方法,调用时,仍然调用的是重写以后的方法
	s.method2() ;
	// 知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法
	// 那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法-->类优先原则
	// 知识点4:如果实现类没有继承类,但是实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错--->接口冲突
	s.method3() ;
	
}

class SubClass extends SuperClass implements CompareA,CompareB {
     
	pubilc void method3(){
     
		System.out.println(SubClass:上海) ;
	}
	public void myMethod(){
     
		method3() ;  // 调用自己定义的重写方法
		super.method3() ;   // 调用父类中声明的
		// 调用接口中的默认方法
		CompareA.super.method3() ;
		CompareB.super.method3() ;
		
	}
}

总结

       Java基础部分就到此结束了,东西还是不少的,还有很多问题需要在今后的学习和实践中慢慢积累,此博客适合于有一定java基础,想要快速复习的同学。

       努力准备秋招中,许愿大厂offer!

你可能感兴趣的:(java,java基础,java面试,面向对象,尚硅谷java基础笔记)