Java面向对象

1. 基本概念

  1. 对象

状态:指对象本身的信息

行为:实现对信息的访问/对象的操作

类是一种原型,一种抽象,一个共性,一个模板

类和对象的关系

  • 对象是具体的,是其所属的累的某个具体实现
  • 必须先有类才能创建对象
  • 类是静态的,而对象是动态的
  1. 封装性
  • 对象的某些状态呗保护/隐藏,其他对象无法直接访问。

  • 其他对象只能通过该对象的方法(即接口,interface)去访问被保护的状态

  • 好处

模块化:每个对象的源文件可以相互独立,可以被不同的程序调用,每个对象是一块积木,可以搭建不同的形状。

信息隐藏:被定义为公共属性的数据和方法才能被其他对象访问,否则不能访问。

  • 黑盒对象的使用者无需知道其使用的对象的运作细节。
  1. 继承

单继承

  • 一个类A写好后,要编写另一个类B,B有A的所有特性(可能还有A没有的特性)。
  • B继承A ,然后加入A所没有的特性
  • 青出于蓝而胜于蓝
  1. 重载
  • 构成重载的条件:

满足下列条件的多个方法相互构成重载:
1.多个方法在同一个类中
2.多个方法具有相同的方法名
3.多个方法的参数不同,类型不同或者数量不同
4.多个方法可以有不同的访问权限修饰符
注意:构成重载与方法的返回值无关,方法的返回值类型不能作为判断构成重载的依据。

1
[类的修饰符]class 类名[extends 父类名] implements[接口名]{}

如果不写父类,默认父类是Object

一个类只能继承一个父类,实现多个接口

2. 访问控制修饰符

修饰符 当前类 同一包内 子孙类(同一包) 子孙类(不同包) 其他包
public Y Y Y Y Y
protected Y Y Y Y/N N
default Y Y Y N N
private Y N N N N

特别强调:

子类与基类在同一个包中:被声明为protected的变量方法和构造器能被同一个包中的任何其他类访问。

子类与基类不在同一个包中:那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问实例的protected方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package abc;
class A{
protected int x;
protected void print(){}
}

package xyz;
class B extends A{
void test(A a,B b){
a.x = 100;//不合法
a.print();//不合法
b.x = 100;//合法
b.print();//合法
}
}

protected可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)

接口及接口的成员变量和成员方法不能声明为protected

访问控制和继承

  1. 父类中声明为public的方法在子类中也必须是public
  2. 父类中声明为protected的方法在子类中要么声明为protected,要么声明为public,不能声明为private。
  3. 父类中声明为private的方法,不能够被子类继承

3. 非访问修饰符

static修饰符

  • 静态变量

static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。

  • 静态方法

static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

final修饰符

  • final变量

final 表示”最后的、最终的”含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值。

final 修饰符通常和 static 修饰符一起使用来创建类常量。

  • final方法

父类中的final方法可以被子类继承,但是不能被子类重写。声明final方法的主要目的防止该方法的内容被修改。

  • final类

final类不能被继承,没有类能够继承final类的任何特性。

abstract类

  • 抽象类

抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。

一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。

抽象类可以包含抽象方法和非抽象方法。

  • 抽象方法

抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供。

抽象方法不能被声明成 final 和 static。

任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。

如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。

抽象方法的声明以分号结尾,例如:public abstract sample();

4. 多态(重写与重载)

重写(Override)

重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。

外壳不变,核心重写

重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Animal{
public void move(){
System.out.println("动物可以动");
}
}
class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal();
Animal b = new Dog();
a.move();
b.move();
}
}
/*输出
动物可以移动
狗可以跑和走
*/

尽管b属于Animal类型,但是它运行的事Dog类中的方法。

这是由于在编译阶段,只是检查参数的引用类型。

然而在运行时,Java虚拟机指定对象的类型并且运行该对象的方法。

因此在上面的例子中,之所以能编译成功,是因为Animal类中存在move方法,然而运行时,运行的是特定对象的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}

class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
public void bark(){
System.out.println("狗可以吠叫");
}
}

public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象
a.move();// 执行 Animal 类的方法
b.move();//执行 Dog 类的方法
b.bark();//会报错
}
}

重写规则

  1. 参数列表与被重写方法的参数列表必须完全相同
  2. 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类
  3. 访问权限不能比父类中被重写的方法的访问权限更低,例:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
  4. 父类成员方法只能被他的子类重写
  5. 声明为final的方法不能被重写
  6. 声明为static的方法不能被重写,但是能够被再次声明
  7. 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明privatefinal的方法。
  8. 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 publicprotected的非 final 方法。
  9. 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  10. 构造方法不能被重写
  11. 如果不能继承一个类,则不能重写该类的方法。

重载(Overload)

在一个类里面,方法名字相同,而参数不同。返回类型也可以不同。

每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。

最常用的地方就是构造器的重载。

重载规则
  1. 被重载的方法必须改变参数列表(参数个数或类型不一样)
  2. 被重载的方法可以改变返回类型
  3. 被重载的方法可以改变访问修饰符
  4. 被重载的方法可以声明新的或更广的检查异常
  5. 方法能够在同一个类中或者在一个子类中被重载
  6. 无法以返回值类型作为重载函数的区分标准
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Overloading {
public int test(){
System.out.println("test1");
return 1;
}

public void test(int a){
System.out.println("test2");
}

//以下两个参数类型顺序不同
public String test(int a,String s){
System.out.println("test3");
return "returntest3";
}

public String test(String s,int a){
System.out.println("test4");
return "returntest4";
}

public static void main(String[] args){
Overloading o = new Overloading();
System.out.println(o.test());
o.test(1);
System.out.println(o.test(1,"test3"));
System.out.println(o.test("test4",1));
}
}

重写与重载的区别

区别点 重载方法 重写方法
参数列表 必须修改 一定不能修改
返回类型 可以修改 一定不能修改
异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常
访问 可以修改 一定不能做更严格的限制

多态的总结

方法的重写(Overriding)重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  1. 方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
  2. 方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
  3. 方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

变量的作用域

  1. 变量的作用域是指能够访问该变量的上下边界
  2. 可以在类的任何位置声明变量
  3. Java中的变量可以分为:成员变量、局部变量

父类创建子类实例化

12199

抽象类

接口和类的相似点

  1. 一个接口可以有多个方法
  2. 接口文件保存在.java结尾的文件中,文件名使用接口名。
  3. 接口的字节码文件保存在.class结尾的文件中
  4. 接口相应的字节码文件必须在与包名称相匹配的目录结构中

接口与类的区别

  1. 接口不能实例化对象
  2. 接口没有构造方法
  3. 接口中所有的方法必须是抽象方法,Java 8 之后可以使用default关键字修饰非抽象方法
  4. 接口不能包含成员变量,除了staticfinal变量
  5. 接口不是被类继承了,而是被类实现。
  6. 接口支持多继承

接口特性

  1. 接口中的每一个方法是隐式抽象,指定为public abstract
  2. 接口中可以含有变量,隐式指定为public static final
  3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口。

抽象类和接口的区别:

  1. 正常来说抽象类可以有方法体,即可以实现方法的具体功能,但是接口中的方法不行。JDK1.8后,接口里可以有静态方法和方法体了
  2. 抽象类中的变量可以是各种类型的,而接口中的成员变量只能是public static final
  3. 接口中不能含有静态代码块及静态方法,(JDK1.8之后可以)而抽象类是可以有静态代码块和静态方法。
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口

第一题

  • 分别求三个字符串的长度。str.length()
  • 取最小长度
  • 对三个字符串从前往后扫描进行判断。截止条件就是最小长度的前一位。
  • 如果碰到不一样的字符,那么前面的字符串即为所求。

第二题

  • 定义一个新数组

  • 定义两个扫描指针,分别从两个数组首位开始扫描。谁小把谁放到新数组中,然后该数组指针后移一位,另一个数组指针不变,然后在做比较,以此类推。

  • 最后如果一个数组扫描结束,而另一个数组还有元素未被扫描,那么直接将其剩余的数组元素依次放到新数组中