继承

允许创建分等级层次的类
继承就是子类继承父类的属性方法,使得子类对象(实例)具有父类的实例域和方法,或者子类从父类继承方法,使得子类具有父类相同的行为。(拥有了父类的地址)
创建子类的时候会自动开辟父类的内存空间

限制

Java 中只有单继承和多重继承,没有多继承。
子类只可以访问 public 和 protected 修饰的属性和方法。

super 详解

  • 通过 super 访问父类的构造方法;调用 super 构造方法的代码,必须写在子类构造方法的第一行(不能和this(); 同时调用)
  • 通过 super 访问父类的属性
  • 通过 super 访问父类的构造方法

重写(override)

  • 参数列表必须完全与被重写方法的相同
  • 返回值类型必须完全与被重写方法的返回值类型相同
  • 访问权限不能比父类中被重写的方法的访问权限更低
  • 父类的成员方法只能被他的子类重写(无继承)
  • 声明为 static 和 private 的方法不能被重写,但是可以被再次声明。

重载(overload)

Java 中重写(子父类中)和重载(一个类中多个方法名称相同,参数类型不同)的区别

  • 发生的位置不同

重载:一个类中
重写:子父类

  • 参数列表的限制不同

重载:不同
重写:相同

  • 返回值类型

重载:无关
重写:必须一致

  • 访问权限不同

重载:无关
重写:

  • 异常处理

重载:与异常无关
重写:异常范围更小,但是不能抛出新的异常

  1. package week2;
  2. public class Demo5 {
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. Student s = new Student();
  6. s.setName("赵四");
  7. s.setAge(18);
  8. s.say();
  9. }
  10. }
  11. class People{
  12. private String name;
  13. private int age;
  14. public String getName() {//shift+Alt+s 快捷键
  15. return name;
  16. }
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. public int getAge() {
  21. return age;
  22. }
  23. public void setAge(int age) {
  24. this.age = age;
  25. }
  26. public People() {
  27. super();
  28. }
  29. public People(String name, int age) {
  30. super();
  31. this.name = name;
  32. this.age = age;
  33. }
  34. public void say() {
  35. System.out.println("我是:"+name+",我今年"+age+"岁了。");
  36. }
  37. }
  38. class Student extends People{
  39. public Student(){
  40. super("匿名", 18);
  41. super.sex = "男";
  42. super.setName("ahahh ");
  43. }
  44. }

final 关键字

  • 用于修饰属性,变量。

变量成为了常量,无法再次对他进行赋值,
修饰的局部变量只能赋值一次,
修饰的成员变量,必须在声明的时候赋值
全局常量 public static final MAX_NAME

  • 用于修饰类

final 修饰的类,不可以被继承

  • 用于修饰方法

final 修饰的方法,不能被子类重写
final int a = 10;

抽象类

概念

抽象类必须使用 abstract class 声明
不能被实例化:

  • 抽象类本身是不能直接进行实例化操作的,即:不能直接使用关键字new完成。
  • 一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须覆写(重写)抽象类中的全部抽象方法。

格式:

  1. abstract class 类名{ //抽象类
  2. }

抽象方法

  1. abstract class 类名{
  2. public abstract void main(); //抽象方法,只声明而为实现
  3. }

常见问题

  • 抽象类能否有构造方法?

能有构造方法,而且子类对象实例化的时候的流程与普通类的继承是一样的,都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法。

  • 抽象类能否使用final声明?

不能,因为final属修饰的类是不能有子类的 , 而抽象类必须有子类才有意义,所以不能。

抽象类和普通类区别

  • 抽象类必须用public或protected修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。 默认缺省为 public
  • 抽象类不可以使用new关键字创建对象, 但是在子类创建对象时, 抽象父类也会被JVM实例化。
  • 如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么子类也必须定义为 abstract类

接口

概念

如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口。只允许抽象方法

  1. interface 接口名称{
  2. 全局常量;
  3. 抽象方法;
  4. }

面向接口的编程思想

这种思想是接口是定义(规范,约束)与实现(名实分离的原则)的分离。

  • 降低程序的耦合性
  • 易于程序的扩展
  • 有利于程序的维护

简写

因为接口本身都是由全局常量和抽象方法组成 , 所以接口中的成员定义可以简写:
1、全局常量编写时, 可以省略public static final 关键字,例如:
public static final String INFO = "内容" ;
简写后:
String INFO = "内容" ;
2、抽象方法编写时, 可以省略 public abstract 关键字, 例如:
public abstract void print() ;
简写后:
void print() ;

接口的实现 implements

可以多实现
格式:
class 子类 implements 父接口1,父接口2...{
}
以上的代码称为接口的实现。那么如果一个类即要实现接口,又要继承抽象类的话,则按照以下的格式编写即可: class 子类 extends 父类 implements 父接口1,父接口2...{
}

接口的继承

接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承,例如:
interface C extends A,B{
}
如果一个接口要想使用,必须依靠子类。 子类(如果不是抽象类的话)要实现接口中的所有抽象方法。
**

接口和抽象类的区别

  • 抽象类要被子类继承,接口要被类实现。
  • 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。
  • 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
  • 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
  • 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
  • 接口不能有构造方法,但是抽象类可以有

多态

对象的多种表现形式

多态的体现

对象的多态性,从概念上非常好理解,在类中有子类和父类之分,子类就是父类的一种形态 ,对象多态性就从此而来。
ps: 方法的重载 和 重写 也是多态的一种, 不过是方法的多态(相同方法名的多种形态)。
重载: 一个类中方法的多态性体现 重写: 子父类中方法的多态性体现。

多态的使用:对象的数据类型转换

类似于基本数据类型的转换:

  • 向上转型:将子类实例变为父类实例 |- 格式:父类 父类对象 = 子类实例 ;
  • 向下转型:将父类实例变为子类实例 |- 格式:子类 子类对象 = (子类)父类实例 ;

instancof

作用: 判断某个对象是否是指定类的实例,则可以使用instanceof关键字
格式: 实例化对象 instanceof 类 //此操作返回boolean类型的数据

  1. public class Demo2{
  2. public static void main(String[] aegs) {
  3. Nurse n = new Nurse();
  4. say(n);
  5. Student s = new Student();
  6. say(s);
  7. }
  8. public static say(Person p) {
  9. //判断传入的对象是此类型的哪种形态(哪个子类的对象)
  10. if(p instanceof Student) {
  11. Student s = (Student)p;
  12. s.say();
  13. }else {
  14. System.out.println("必须传入学生形态,才可以执行");
  15. }
  16. }
  17. }

Object 类

概念

Object类是所有类的父类(基类),如果一个类没有明确的继承某一个具体的类,则将默认继承Object类。
例如我们定义一个类:
public class Person{
}
其实它被使用时 是这样的:
public class Person extends Object{
}

Object 的多态

使用Object可以接收任意的引用数据类型(万物)

API 的使用

ctrl+鼠标左键 查看类的源码

toString

建议重写Object中的toString方法。 此方法的作用:返回对象的字符串表示形式。 Object的toString方法, 返回对象的内存地址

equals

建议重写Object中的equals(Object obj)方法,此方法的作用:指示某个其他对象是否“等于”此对象。
Object的equals方法:实现了对象上最具区别的可能等价关系; 也就是说,对于任何非空引用值x和y ,当且仅当 x和y引用同一对象( x == y具有值true )时,此方法返回true 。

equals方法重写时的五个特性:

  • 自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
  • 对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。
  • 传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后 x.equals(z)应该返回true 。
  • 一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前提是未修改对象 上的equals比较中使用的信息。
  • 非空性 :对于任何非空的参考值x , x.equals(null)应该返回false 。
  1. public boolean equals(Object obj) {
  2. if(this == obj) {
  3. return true;
  4. }
  5. if(obj == null) {
  6. return false;
  7. }
  8. if(obj instanceof Person) {//类型相同
  9. Person p2 = (Person) obj;
  10. if(this.name.equals(p2.name) && this.age ==p2.age) {
  11. //相同
  12. return true;
  13. }
  14. }
  15. return false;
  16. }
  17. shift + alt + s
  18. public boolean equals(Object obj) {
  19. if (this == obj)//自反性
  20. return true;
  21. if (obj == null)//非空性
  22. return false;
  23. if (getClass() != obj.getClass())//类型一样
  24. return false;
  25. Person other = (Person) obj;
  26. if (age != other.age)
  27. return false;
  28. if (name == null) {
  29. if (other.name != null)
  30. return false;
  31. } else if (!name.equals(other.name))
  32. return false;
  33. return true;
  34. }

内部类

以文字方式去理解
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。

成员内部类

成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问 的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法

  1. package lei;
  2. public class Demo1 {
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. Outer o = new Outer();//先创建外部类
  6. o.setX(100);
  7. Outer.Inner i = o.new Inner();
  8. i.say();
  9. }
  10. }
  11. class Outer {
  12. private int x;
  13. public int getX() {
  14. return x;
  15. }
  16. public void setX(int x) {
  17. this.x = x;
  18. }
  19. class Inner{
  20. private int x = 200;
  21. public void say() {
  22. System.out.println(x);
  23. System.out.println(Outer.this.x);
  24. }
  25. }
  26. }

局部内部类

是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或 者该作用域内。
局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

  1. package lei;
  2. public class Demo1 {
  3. public static void main(String[] args) {
  4. class PersonImp implements Person1{
  5. @Override
  6. public void say() {
  7. // TODO Auto-generated method stub
  8. System.out.println("xinbian");
  9. }
  10. }
  11. PersonImp p = new PersonImp();
  12. haha(p);
  13. }
  14. public static void haha(Person1 p) {//方法要一个类型的对象,不知道new什么,创建一个内部类
  15. p.say();
  16. }
  17. }
  18. public interface Person1 {
  19. public void say();
  20. }

匿名内部类

用来创建一次对象

  • 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或 者实现一个接口。
  • 匿名内部类中是不能定义构造函数的。
  • 匿名内部类中不能存在任何的静态成员变量和静态方法。
  • 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
  • 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
  • 只能访问 final 型的局部变量,1.8之后默认改成常量,内部类会被单独被编写成一个字节码文件,为了使文件中的a与外部的值是一样的,系统就会限制他绝对不可更改。 ```java new 父类构造器(参数列表)|实现接口() { // 匿名内部类的类体部分 }

public class Demo1 {

  1. public static void main(String[] args) {
  2. Person1 p = new Person1() {//只是用一次
  3. public void say() {
  4. System.out.println("人间正道");
  5. }
  6. };
  7. haha(p);
  8. }
  9. public static void haha(Person1 p) {//方法要一个类型的对象,不知道new什么,创建一个内部类
  10. p.say();
  11. }

}

  1. <a name="gJDJM"></a>
  2. ### 静态内部类
  3. 成员内部类加了一个 static修饰,静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。<br />静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员 变量或者方法.
  4. ```java
  5. package lei;
  6. public class Demo1 {
  7. public static void main(String[] args) {
  8. // TODO Auto-generated method stub
  9. Book.Info info = new Book.Info();
  10. info.say();
  11. }
  12. }
  13. public class Book {
  14. static class Info{
  15. public void say() {
  16. System.out.println("信息类");
  17. }
  18. }
  19. }

包装类

捕获.PNG

int i = Interger.parseInt("123");

装箱和拆箱操作

将一个基本数据类型变为包装类,那么这样的操作称为装箱操作。
将一个包装类变为一个基本数据类型,这样的操作称为拆箱操作,

方法的可变参数

可以根据需要自动传入任意个数的参数
语法:
返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}
注意: 可变参数只能出现在参数列表的最后

  1. public class Demo1 {
  2. public static void main(String[] args) {
  3. System.out.println(sum(1,23,4));
  4. System.out.println(sum(1,2));
  5. }
  6. public static int sum(int... nums) {
  7. int n = 0;
  8. for(int i=0; i<nums.length; i++) {
  9. n+=nums[i];
  10. }
  11. return n;
  12. }
  13. }

递归

实现5的阶乘

  1. public class DiGui {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub
  4. int a = fact(5);
  5. System.out.println(a);
  6. }
  7. public static int fact(int n) {
  8. if(n==1) {
  9. return 1;
  10. }else {
  11. return n*fact(n-1);
  12. }
  13. }
  14. }