Java面向对象(中)
1.Eclipse快捷键
- Eclipse中的快捷键:
- 1.补全代码的声明:alt + /
- 2.快速修复: ctrl + 1
- 3.批量导包:ctrl + shift + o
- 4.使用单行注释:ctrl + /
- 5.使用多行注释: ctrl + shift + /
- 6.取消多行注释:ctrl + shift + \
- 7.复制指定行的代码:ctrl + alt + down 或 ctrl + alt + up
- 8.删除指定行的代码:ctrl + d
- 9.上下移动代码:alt + up 或 alt + down
- 10.切换到下一行代码空位:shift + enter
- 11.切换到上一行代码空位:ctrl + shift + enter
- 12.如何查看源码:ctrl + 选中指定的结构 或 ctrl + shift + t
- 13.退回到前一个编辑的页面:alt + left
- 14.进入到下一个编辑的页面(针对于上面那条来说的):alt + right
- 15.光标选中指定的类,查看继承树结构:ctrl + t
- 16.复制代码: ctrl + c
- 17.撤销: ctrl + z
- 18.反撤销: ctrl + y
- 19.剪切:ctrl + x
- 20.粘贴:ctrl + v
- 21.保存: ctrl + s
- 22.全选:ctrl + a
- 23.格式化代码: ctrl + shift + f
- 24.选中数行,整体往后移动:tab
- 25.选中数行,整体往前移动:shift + tab
- 26.在当前类中,显示类结构,并支持搜索指定的方法、属性等:ctrl + o
- 27.批量修改指定的变量名、方法名、类名等:alt + shift + r
- 28.选中的结构的大小写的切换:变成大写: ctrl + shift + x
- 29.选中的结构的大小写的切换:变成小写:ctrl + shift + y
- 30.调出生成getter/setter/构造器等结构: alt + shift + s
- 31.显示当前选择资源(工程 or 文件)的属性:alt + enter
- 32.快速查找:参照选中的Word快速定位到下一个 :ctrl + k
- 33.关闭当前窗口:ctrl + w
- 34.关闭所有的窗口:ctrl + shift + w
- 35.查看指定的结构使用过的地方:ctrl + alt + g
- 36.查找与替换:ctrl + f
- 37.最大化当前的View:ctrl + m
- 38.直接定位到当前行的首位:home
- 39.直接定位到当前行的末位:end
2.继承性 面向对象的特征二
2.1 继承性的优点
- 减少代码的冗余,提高了代码的复用性
- 便于功能的扩展(子类会有更多的功能)
- 为之后多态性的使用,提供了前提
格式:class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
2.2体现
- 子类A继承父类B后,子类A就获取了父类B中声明的所有的属性和方法。特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构。
- 子类继承父类以后,还可以声明自己特有的属性和方法,实现功能的扩展。
2.3关于继承的规定
Java只支持单继承和多层继承,不允许多重继承
- 一个类可以被多个子类继承
- 一个子类只能有一个直接父类,但是可以有"爷爷",即间接父类
- 子类继承父类以后,就获取了直接父类和间接父类的所有属性和方法
2.4 Object类
- 如果我们没有显式的声明一个类的父类的化,则此类继承于java.lang.Object类
- 所有的java类(除java.lang.Object类)都直接或间接继承Object类
- 意味着所有的类都具有Object的属性和方法
3. Debug的一些知识
- step over 如果有函数,会当成一条语句来执行
- step into 如果有函数,会进入到函数中执行
- step return 退出当前正在执行的函数
- resume 执行到下一个断点的位置处
- drop 同、
- frame 回到当前行所在方法的第一行
4. 方法的重写(override/overwrite)
4.1 初步理解
- 概念:在子类中根据需要对从父类中继承来的方法进行改造,也称为方法的重置、覆盖。
- 实现方法:在子类中写与父类同名同参的方法
- 子类对象调用方法时,使用的是重写后的方法
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("吃饭");
}
}
public class Student extends Person{
public Student(){
}
//对Person类中的eat方法进行了重写override
public void eat(){
System.out.println("学生要多吃有营养的东西");
}
}
4.2重写的规定
方法的声明: 权限修饰符 (final static …)返回值类型 方法名(形参列表) throws 异常类型{
//方法体
}
- 约定:子类中的称为重写的方法,父类中的称为被重写的方法
- 子类重写的方法名和形参列表与父类被重写的方法名和形参列表相同
- 子类重写的方法的权限修饰符不小于父类中方法的权限修饰
(想要覆盖,权限必须不小于父类)
特殊的:子类不能覆盖父类中private的方法 - 返回值类型:
若父类被重写的方法返回值为void,则子类重写的方法的返回值也为void
若父类别重写的方法返回值为基本数据类型,则子类重写方法的返回值类型为相同的返回值类型
若父类被重写的方法的返回值为A类,则子类重写方法的返回值为A类或A的子类
- 子类抛出的异常类型不大于父类被重写方法抛出的异常类型
- 子类和父类中同名同参的方法要么都是非static,要么都是static的(不是重写),即只有非static才有重写一说
5. super 关键字
5.1 super的理解
- super可以理解为父类的,(类似于this可以理解为当前对象的…)
super可以用来调用父类的属性、方法、构造器 - 使用:在子类的方法或构造器中,使用super.属性或super.方法显示的使用。通常情况下没有重名,是省略的
- 特殊的,当子类和父类有同名的属性时,要在子类中调用父类中的属性,需要使用super.属性
- 注意:这里的父类包括间接父类
- 查找的顺序是这样的,先在当前类中找,然后在直接父类找,然后再找间接父类,一层层往上,直到找到想要的属性或方法为止
5.2 super调用父类的属性和方法
//super调用父类的属性和方法
public class Person{
int id;
public void eat(){
System.out.println("吃饭");
}
}
public class Student{
int id; //属性不存在重写
public void showId(){
//在子类中使用父类中重名的属性,需要使用super
System.out.println("身份证号"+super.id+"学号"+this.id);
}
public void eat(){
System.out.println("学生要多吃饭吃饭");
}
public void showEat(){
System.out.println("在子类中对方法进行了重写");
System.out.println("想调用父类中被重写的eat方法
,需要使用super.属性");
super.eat();
}
}
5.3 super调用构造器
- super(形参列表)的使用必须放在子类构造器的首行
- 而this()也只能放在首行,所以super(),this()二选一
- 如果在当前构造器的首行没有显式地使用this/super,那么默认调用空参的super构造器super()
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
}
class Student{
private String major;
public Student(String name,int age,String major){
//调用父类中的构造器
super(name,age);
this.major = major;
}
}
6. 多态性 面向对象特征之三
可以理解为一个事物的多种形态
- 对象的多态性:把new出来的子类对象赋给父类定义的变量(或者说父类的引用指向子类的对象)
- 例如Person p = new Man();
- 虚拟方法调用:当调用子父类同名同参的方法时,实际执行的是子类中重写的方法
- 子类中特有的方法是不能调用的
6.1 多态的前提
- 有类的继承关系
- 有方法的重写
6.2 多态的使用:虚拟方法调用(动态绑定)
在编译器只能调用父类中声明的方法,但是实际执行的是子类重写父类的方法
- 多态的情况下,父类中的方法称为虚拟方法,父类根据被赋予的子类对象,动态调用该子类的方法。
- 在编译时是无法确定实际使用的方法,运行的时候才能确定使用哪个子类的方法,所以说多态是一种运行时行为
- 在编译的时候能确定的称为“早绑定”、“静态绑定”
- 对象的多态性只适用于方法,不适用于属性;即如果父类和子类中有同名的属性,那么使用多态调用的属性是父类的属性
对于方法:编译看左边,运行看右边
对于属性:编译运行都看左边
//对象的多态性:父类的引用指向子类的对象
Person p1 = new Man();
Person p2 = new Woman();
p1.eat(); //调用的是Man中重写的方法
//p1.manSmoke(); //使用子类中特有的方法编译不能通过
//多态性的举例
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
test.show(new Dog());
test.show(new Cat());
}
//参数是Animal类型的,可以提高方法的复用性
//Animal的子类也可以当作参数传给这个方法
public void show(Animal animal){
animal.shout();
}
}
class Animal{
public void shout(){
System.out.println("动物叫声");
}
}
class Dog extends Animal{
public void shout(){
System.out.println("汪汪汪");
}
}
class Cat extends Animal{
public void shout(){
System.out.println("喵喵喵");
}
}
在方法的形参中使用父类,赋值的时候它的子类都可以当作形参传入,使得方法的复用性大大提高
6.3 向下转型
Person p = new Man();
当我们使用上述多态时,无法使用Man中特有的属性,但是我们在new Man()时,Man中的属性是存在的,创建在堆中。为了使用Man中特有的属性和方法,需要使用向下转型。
向下转型和数据类型的强转有相似之处
Person p = new Man();
Man m = (Man) p;
//将p从Person类型转化为Man之后,Man中特有的属性和方法都可以调用了
p.isSmoke = false; //isSmoke 是Man特有的属性
p.earnMoney(); //earnMoney是Man特有的方法
- 但是向下类型转化有风险,比如将上面的p转化为Woman类型,然后使用Woman类中特有的属性和方法,会出现ClassCastException的异常
- 为了避免这个错误需要使用instanceof关键字
6.4 instanceof 关键字
引入目的:为了防止向下转型出现ClassCastException的异常
判断对象a是否是类A的实例。如果是,返回true;否则返回false
a instanceof A;如果a instanceof A为真,且B为A的父类,那么a instanceof B也为真
if(a instanceof A == true)
if(A是B的子类)
then (a instanceof B == true)
Person p = new Man();
if(p instanceof Man){
Man p2 = (Man) p;
System.out.println("这是一个男人,向下转型成功");
p2.earnMoney();
}
7. Object类的使用
- Object类是所有类的父类,是继承树的根节点,定义在java.lang.Object包下
- Object只声明了一个空参构造器
- Object类没有属性
Object类中的一些方法
toString()
equals()
clone()
finalize()
getClass()
hashCode()
notify()
notifyAll()
wait()
7.1 equals()方法
7.1.1 == 的用法
- == 可以使用在基本数据类型和引用数据类型变量中
- 如果比较的是基本数据类型变量:比较2个变量保存的数据是否相等(数据类型不一定要相同)
- 如果比较的是两个引用数据类型,那么比较的是地址值是否相等,即两个变量是否指向同一个对象实体
Customer cust1 = new Customer("Tom",21);
Customer cust2 = new Customer("Tom",21);
System.out.println(cust1 == cust2); //false
7.1.2 equals()
- 是方法,而非运算符
- 只能适用于引用数据类型
- Object类中equals方法的定义和 == 的作用相同
public boolean equals(Object obj){
return (this == obj);
}
Customer cust1 = new Customer("Tom",21);
Customer cust2 = new Customer("Tom",21);
//使用equals方法
System.out.println(cust1.equals(cust2)); //false
String str1 = "Tom";
String str2 = "Tom";
System.out.println(str1.equals(str2)); //true
- 原因:对于String类中的equals方法进行过了重写
- 像String,Date,File,包装类等都重写了Object类中的equals()方法,比较的不再是地址值是否相同,而是内容是否相同
- 通常,自定义类中如果使用equals方法,需要的往往是比较内容而非地址,使用需要重写equals方法
- 重写的原则:比较对象的数据是否相同
- 可以使用IDE自动生成equals方法
7.2 toString方法
- 当我们输出一个对象的引用时,实际就是调用当前对象的toString()
- Object类中的定义的toString方法:类名@虚拟地址值
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- String,Date,File,包装类中都重写了Object类中的toString方法,使得调用toString方法时,返回实体内容信息(也就是用户实际想要的信息,而不是地址)
8. 单元测试方法
Java中JUnit单元测试
步骤
- 选中当前工程 - 右键选择:build path - add libraries - JUnit4 - 下一步
- 创建Java类进行单元测试
测试类的要求:
- public
- 提供public的无参构造器
- 在此类中声明单元测试方法
单元测试方法的要求:
- public
- 没有返回值
- 没有形参
- 此单元测试方法上需要声明注解@Test,并在单元测试类中导入import org.junit.Test;
- 注意:一定要先写@Test,再写方法名等内容
- 在方法体内写测试代码
- 左键双击测试方法名,右键run as JUnit Test
结果说明:
- 没有任何异常:绿条
- 出现异常:红条
9. 包装类 Wrapper
- 针对8种基本数据类型定义相应的引用类型——包装类(封装类)
基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
9.1 基本数据类型、包装类、String三者之间的转化
- 基本数据类型和包装类:自动装箱\拆箱
//自动装箱
int num = 10;
Integer in = num;
//自动拆箱
Double d1 = new Double(3.14);
double d2 = d1;
- 基本数据类型和字符串
//基本数据类型转化为字符串:连接运算
String str = 123+"";
//字符串转化为基本数据类型
//调用String的方法parseXxx,如ParseInt
int num = String.parseInt("2345");
- 包装类与字符串
//包装类转化为字符串
//调用包装类的toString方法
Integer in1 = new Integer(123);
String str = in1.toString();
//字符串转化为包装类
//即利用字符串创建包装类
Integer in2 = new Integer(str);
9.2 包装类的面试题
Integer类内部定义了IntegerCache结构,IntegerCache中定义了Integer[],存储了常用的int类型的数字,范围是-128 - 127
- 在范围内,直接在Integer内部给你new好了
- 在这个范围外的数字需要另外new。
Integer m = 1;
Integer n = 1;
System.out.println(m==n); //true,因为IntegerCache结构中new好了
Integer x = 128;
Integer y = 128;
System.out.println(x==y); //false,因为不在IntegerCache结构定义的数组范围内(-128到127)