Part1 面向对象(下)
一、抽象类和抽象方法
1. 抽象方法
使用abstract修饰的方法,没有方法体,只有方法声明,定义的是一种“规范”,要求子类提供具体的实现。
2.抽象类
包含抽象方法的类就是抽象类,同样需要用abstract修饰。有抽象方法的类一定要定义为抽象类,但抽象类可以没有抽象方法,抽象类内也可以包含具体实现的方法。抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象,以这个类作为模板,可以避免子类设计的随意性。
3.抽象方法和抽象类的要点
- 抽象类不能实例化,即不能通过new创建对象,只能被继承。
- 抽象类可以包含方法(普通方法和抽象方法)、成员变量、构造方法、初始化块、内部类(接口、枚举),但构造方法不能用来new对象,只能用来被子类调用。
- 抽象类只能被继承。
- 抽象方法必须被子类实现。
- 含有抽象方法的类(直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法)只能被定义为抽象类。
- 使用abstract修饰类时,表明这个类只能被继承,修饰方法时,表明这个方法必须由子类提供实现。但final修饰的类不能被继承,final修饰的方法不能被重写,因此abstract和final不能同时使用。
- abstract只能修饰类或者方法,不能修饰变量、构造方法等。
- 当使用static修饰方法时,可以通过类调用这个方法,但如果这个方法又被abstract修饰,调用一个没有方法体的方法会出现错误,所以static和abstract不能修饰同一个方法。但它们不是绝对互斥的,它们可以同时修饰内部类。
abstract修饰的方法必须被子类重写才有意义,因此abstract方法不能被private修饰,即private和abstract不能同时修饰方法。
//抽象类abstract class Animal{private int age;abstract public void shout();//抽象方法,具体的子类实现方法不一样,这里只提供这个方法的抽象public void run(){System.out.println("运动");}}class Dog extends Animal{//子类必须实现父类的抽象方法,否则编译报错public void shout(){System.out.println("旺旺旺");}}public class Test {public static void main(String[] args) {Dog d = new Dog();d.shout();//调用子类的实现}}
二、接口(Interface)
1.接口的概念
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行得更彻底,则可以提炼出一种更加特殊的“抽象类”——接口,接口定义的是一组规范,接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要,可见接口是从多个相似类中抽象出来的规范,这样可以更加规范地对子类进行约束,全面地专业地实现了规范和具体实现的分离。如:Type-c接口是指遵守了Type-C规范的插槽,而具体的Type-c充电插槽只是Type-C接口的实例,只要遵守这个接口规范,就可以保证能正常充电。面向对象的精髓,就是对对象的抽象,最能体现这点的就是接口。
抽象类中还提供某些具体的实现,而接口不提供任何具体实现,接口中的所有方法都是抽象方法,接口完全是面向规范的。接口是定义两个模块之间的通信标准,通信间的规范,如果把设计的模块间的接口定义后,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现。2.三种类的区别
普通类:具体实现
- 抽象类:具体实现+规范(抽象方法)
-
3.接口的定义
Java9以前的版本
[修饰符] interface 接口名 [extends 父接口1,父接口2...]{零个到多个常量定义;零个到多个抽象方法定义;}
定义接口的详细说明:
修饰符:只能是public或默认
接口名:和类名相同命名机制
extends:接口可以多继承
常量:接口中的属性只能是常量,总是public static final,可省略,默认就是常量
方法:接口中的方法只能是public abstract ,可省略,默认为抽象方法//飞行接口interface Volant{int FLY_HEIGHT = 100;//总是public static final类型的void fly();//总是public abstract void fly()类型的}//善良接口interface Kind{void helpOthers();}//子类通过implements实现接口中的规范class Angle implements Volant,Kind{//一定要具体实现fly()方法public void fly() {System.out.println("飞飞飞");}//一定要具体实现helpOthers()方法public void helpOthers() {System.out.println("路见不平,拔刀相助");}}
4.要点
子类通过implements实现接口中的规范
- 接口不能创建实例,但是可以用来声明引用变量
- 一个类实现了接口,必须实现接口中的所有方法
- JDK1.8之前(不含8),接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
JDK1.8(含8)以后,接口中可包含普通的静态方法、默认方法,Java9为接口增加了一种私有方法,私有方法的主要作用就是作为工具方法,私有方法可以是类方法也可以是实例方法,为接口中的类方法或默认方法提供支持。类方法、默认方法、私有方法都可以有具体的实现。
5.接口中的静态方法和默认方法(Java8以后)
5.1 默认方法
Java8(包含8)以后,允许给接口添加一个非抽象的方法实现,只需要使用default关键字修饰即可,这个方法叫做默认方法,也叫扩展方法。
默认方法和抽象方法的区别是抽象方法要被实现,而默认方法是在接口里直接实现了,不需要再被实现,当然默认方法可以被继承重写。
注:默认方法和前面的default方法的区别,方法如果不加任何修饰就为default方法,而接口中的默认方法要显式加default修饰。interface A{//显式使用default修饰default void moren(){System.out.println("我是A接口的默认方法");}}public class Test implements A{@Overridepublic void moren(){System.out.println("重写A接口的默认方法");}public static void main(String[] args) {}}
5.2 静态方法
Java8以后,可以在接口中定义静态方法的实现,这个静态方法从属于接口(接口是一种特殊的类),可以通过接口名调用。如果子类中定义同名的静态方法,则是完全不相同的两个方法,从属于子类,通过子类名调用。
interface A{public static void staticMethod(){System.out.println("A中的静态方法");}}class B implements A{public static void staticMethod(){System.out.println("B中的静态方法");}}public class Test {public static void main(String[] args) {A.staticMethod();B.staticMethod();}}//A中的静态方法//B中的静态方法
5.3 默认方法和静态方法的区别
在默认方法中可以直接调用静态方法,而静态方法不能调用默认方法,默认方法就是一个普通方法。(静态成员不能访问非静态成员)
interface A{public static void staticMethod(){System.out.println("A中的静态方法");//moren();//报错}default void moren(){staticMethod();//可调用静态方法}}
6. 接口的多继承
接口完全支持多继承,子接口扩展某个父接口,将会获得父接口所定义的一切。
interface A{void testa();}interface B{void testb();}interface C extends A, B{void testc();}//必须实现C中所有的抽象方法public class Test implements C {@Overridepublic void testa() {}@Overridepublic void testb() {}@Overridepublic void testc() {}}
三、String类
1.String类基础
String类又称为不可变字符序列。
- String类位于java.lang包中,Java程序默认导入java.lang包下的所有类。
- Java字符串就是Unicode字符序列,例如“Java”就是4个Unicode字符‘J’‘a’‘v’‘a’组成的。但要注意,“Java”字符串是一个对象,它同样有很多的方法、属性,不是只有这四个字符,所以一个字符串所占的空间实际上是很大的。
- Java没有内置的字符串类型,而是提供了一个预定义的类String,每个用双引号括起来的字符串都是String类的一个实例。
2.字符串相等判断(使用equals方法)
public class Test {public static void main(String[] args) {String str1 = "abcde";String str2 = new String("abcde");String str3 = "abcde";System.out.println(str1 == str2);//默认使用了toSting()方法System.out.println(str1 == str3);System.out.println(str1);//String类的toSting方法被重写了,这里打印输出的不再是地址System.out.println(str2);System.out.println(str3);}}//false//true//abcde//abcde//abcde

String的对象中用一个Byte数组来存储字符,当然String对象中还有其他属性和方法,所以str1和str2指向的不是同一个对象。但我们比较字符串的时候,一般只要字符串的内容相同就认为是相等的,涉及到字符串比较可以使用equals方法。public class Test {public static void main(String[] args) {String str1 = "abcde";String str2 = new String("abcde");System.out.println(str1.equals(str2));//使用equals则只比较字符串内容}}//true
3.常量池原理
4.String类常用方法详解(本章重点学习这些方法如何使用,多练习)
String类是我们最常使用的类,字符串类的方法我们必须非常熟悉。以下是常用的方法:
| 方法 | 解释说明 |
|---|---|
| char charAt(int index) | 返回字符串中第index个字符 |
| boolean equals(String other) | 判断两个字符串是否相等 |
| boolean equalsIgnoreCase(String other) | 判断两个字符串是否相等(忽略大小写) |
| int indexOf(String str) | 从头到尾查找,返回找到的第一个子字符串的索引位置,如未找到,返回-1。可以用来判断字符串中是否包含该子串 |
| lastIndexOf() | 从尾开始查找,返回找到的第一个子字符串的索引位置,如未找到,返回-1。 |
| int length() | 返回字符串的长度 |
| String replace(char oldChar, char newChar) | 返回一个新串,它是用newChar替换所有的oldChar生成的新的字符串 |
| boolean startWith(String str) | 判断字符串是否以str开头 |
| boolean endsWith(String str) | 判断字符串是否以str结尾 |
| String substring(int beginIndex) | 截取从开始索引到字符串末尾的字符串 |
| String substring(int beginIndex, int endIndex) | 截取从开始索引到结束索引间的字符串,其中包含开始索引这个字符,但不包括结束索引的字符 |
| String toLowerCase() | 返回一个新字符串,该串将原字符串的大写字母改成小写字母 |
| Stirng toUpperCase() | 返回一个新字符串,该串将原字符串的小写字母改成大写字母 |
| String trim() | 返回一个新字符串,该串删除了原串头部和尾部的空格 |
注:String是不可变字符串,所有的替换、截取、去空格、转换大小写都是生成新字符串,原来的字符串不会变化。
public class Test {public static void main(String[] args) {String str1 = "abcdefdef";String str2 = "Abcdefdef";System.out.println(str1.charAt(0));//aSystem.out.println(str1.length());//9System.out.println(str1.charAt(str1.length() - 1));//fSystem.out.println(str1.equals(str2));//falseSystem.out.println(str1.equalsIgnoreCase(str2));//trueSystem.out.println(str1.indexOf("def"));//3System.out.println(str1.lastIndexOf("def"));//6System.out.println(str1.replace("def", "ABC"));//abcABCABCSystem.out.println(str1.startsWith("abc"));//trueSystem.out.println(str1.endsWith("def"));//trueSystem.out.println(str1.substring(1));//bcdefdefSystem.out.println(str1.substring(3,5));//de, 3~(5-1)System.out.println(str1.toUpperCase());//ABCDEFDEFSystem.out.println(str2.toLowerCase());//abcdefdefString str3 = " a b ";System.out.println(str3.trim());//a bSystem.out.println(str3.replace(" ", ""));//ab,去除所有空格System.out.println(str1.replace("def", ""));//abc,删除def}}
