### Javaben get和set方法
#### 开发中封装的简单规则:
- 属性一般使用private 访问权限。
属性私有后, 提供相应的 get/set 方法来访问相关属性,这些方法通常是public 修饰的,以提供对属性的赋值与读取操作(注意:boolean 变量的get方法是 is 开头!)
方法:一些只用于本类的辅助性方法可以用 private 修饰,希望其他类调用的方法用public修饰。
```java
package com.company.encapsulation.b;
//User实现类,Javaben 方法公开,属性私有
public class User {
private int id;
private String name;
private boolean man;
// 创建带参构造器
public User(int id, String name, boolean man) {
this.id = id;
this.name = name;
this.man = man;
}
public void printUserInfo(){
System.out.println(id);
System.out.println(name);
System.out.println(man);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMan() {
return man;
}
public void setMan(boolean man) {
this.man = man;
}
}
//TestUser测试类
package com.company.encapsulation.b;
public class TestUser {
public static void main(String[] args) {
User u = new User(100,"xiaoming",true);
System.out.println(u.getName());
System.out.println(u.isMan());
}
}
```
------
### 多态(polymorphism)详解
- 多态定义:
- 多态指的是同一个方法调用,由于对象不同可能会有不同的行为。现实生活中,同一个方法,具体实现会完全不同。 比如:同样是调用人“吃饭”的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。
- 多态的要点:
1. 多态是方法的多态,不是属性的多态(多态与属性无关)
2. 多态的存在要有 3 个必要条件:继承,方法重写,父类引用指向子类对象。
3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
```java
//定义Animal类和继承重写shout()方法
package com.company.polymorphism;
public class Animal {
public void shout(){
System.out.println("叫了一声");
}
}
class Dog extends Animal{
@Override
public void shout(){
System.out.println("汪汪汪!");
}
public void seeDoor(){
System.out.println("看门中...");
}
}
class Cat extends Animal{
@Override
public void shout() {
System.out.println("喵喵喵!");
}
}
------------------------------------------------------------------------------
//测试不同对象,调用相同的方法,产生不同行为
package com.company.polymorphism;
public class TestAnimal {
public static void main(String[] args) {
animalCry(new Dog());
animalCry(new Cat());
//编译时类型 运行时类型
Animal animal = new Dog();
animal.shout();
// animal.seeDoor();
}
static void animalCry(Animal a) { //Animal a = new Dog() 父类引用指向子类对象
System.out.println("TestAnimal.animalCry");
a.shout(); //可以出现多态
}
}
```
- 对象的转型(casting)
- 父类引用指向子类对象,我们称这个过程为**向上转型**,属于自动类型转换。
- 向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。
这时,我们就需要进行类型的强制转换,我们称之为**向下转型**
```java
//编译时类型 运行时类型
Animal animal = new Dog(); //向上转型(自动)
animal.shout();
Dog d = (Dog) animal; //强制向下转型
d.seeDoor();
```
- 父类引用变量被强制转换成非对应子类对象,编译时不会报错,运行时会报错;
```java
//编译时不会报错,运行时会报错:java.lang.ClassCastException
Animal animal = new Dog();
Cat c = (Cat) animal;
c.catchMouse();
```
![image-20220329181206545](面向对象.assets/image-20220329181206545.png)
- 解决方法:对父类引用变量做类型判断
```java
if(animal instanceof Cat){
Cat c = (Cat) animal;
c.catchMouse();
}
```
### 抽象类和接口
#### 抽象方法和抽象类
- 抽象方法
1. 使用 abstract 修饰的方法,没有方法体,只有声明。
1. 定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。
- 抽象类
1. 包含抽象方法的类就是抽象类。
2. 通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
```java
package com.company.abstractClass;
/**
* 测试抽象类
*/
public abstract class Animal {
int age;
public abstract void rest();
public abstract void run();
public void shout(){
System.out.println("Animal.shout");
};
}
class Dog extends Animal{
@Override
public void rest() {
System.out.println("Dog.rest");
}
@Override
public void run() {
System.out.println("Dog.run");
}
}
class Cat extends Animal{
@Override
public void rest() {
System.out.println("Cat.rest");
}
@Override
public void run() {
System.out.println("Cat.run");
}
}
```
- 抽象类的使用要点:
1. 有抽象方法的类只能定义成抽象类;
1. 抽象类不能实例化,即不能用 new 来实例化抽象类;
3. 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来 new 实例,
只能用来被子类调用。
1. 抽象类只能用来被继承。
1. 抽象方法必须被子类实现。
### 接口interface
- 定义定义:
- 接口就是一组规范(就像我们人间的法律一样)所有实现类都要遵守。
- 面向对象的精髓,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如 C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
![image-20220329183639201](面向对象.assets/image-20220329183639201.png)
接口的作用
- 为什么需要接口?接口和抽象类的区别?
- 接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:**规范和具体实现的分离**。
- 接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。做系统时往往就是使用“面向接口”的思想来设计系统。
- **接口和实现类不是父子关系,是实现规则的关系**。比如:定义一个接口 Runnable,Car 实现它就能在地上跑,Train 实现它也能在地上跑,飞机实现它也能在地上跑。就是说,如果它是交通工具,就一定能跑,但是一定要实现 Runnable 接口。
如何定义和使用接口
- 声明格式:
- [访问修饰符] interface 接口名 [extends] 父接口 1,父接口 2{
常量定义;
方法定义;
}
- 定义接口的详细说明:
☐ **访问修饰符:**只能是 public 或默认。
☐ **接口名:**和类名采用相同命名机制。
☐ **extends:**接口可以多继承。
☐ **常量:**接口中的属性只能是常量,总是:public static final 修饰。不写也是。
☐ **方法:**接口中的方法只能是:public abstract。省略的话,也是 public abstract。
```java
//定义Volant接口
package com.company.testInterface;
//飞行接口
public interface Volant {
/*public static final*/ int FLY_HIGHT = 100;
/*public abstract*/ void fly();
}
//善良接口
interface Honest {
void helpOther();
}
//GoodMan类实现Honest接口
class GoodMan implements Honest {
@Override
public void helpOther() {
System.out.println("乐于助人");
}
}
//BirdMan类实现Volant接口
class BirdMan implements Volant {
@Override
public void fly() {
}
}
/**
* 天使实现了多个接口
*/
class Angel implements Honest, Volant {
@Override
public void fly() {
System.out.println("Angel.fly");
}
@Override
public void helpOther() {
System.out.println("Angel.helpOther");
}
}
------------------------------------------------------------------------------
//测试类创建实例,实现实例的方法
package com.company.testInterface;
public class TestVolant {
public static void main(String[] args) {
Angel angel = new Angel();
angel.fly();
angel.helpOther();
System.out.println(Volant.FLY_HIGHT);
Volant volant = new Angel();
volant.fly();
}
}
```
- 要点:
- 类通过 **implements** 来实现接口中的规范。
- 接口不能创建实例,但是可用于声明引用变量类型。
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是 public 的。
- JDK1.8(不含8)之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
- **JDK1.8(含8)后,接口中包含普通的静态方法、默认方法。**
- 接口中包含普通的静态方法、默认方法。
- 默认方法
- Java 8 及以上新版本,允许给接口添加一个非抽象的方法实现,只需要使用 default 关
键字即可,这个特征又叫做默认方法(也称为扩展方法);
- 默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,
接口可以提供默认方法的实现,所有这个接口的实现类都可以得到默认方法。
```java
package com.company.testInterface;
/**
* 测试接口中的新特性(默认方法)
*/
public interface TestDefault {
public void printInfo();
default void moren(){
System.out.println("测试默认方法");
System.out.println("TestDefault.moren");
}
}
class TestDefaultClass implements TestDefault{
@Override
public void printInfo() {
System.out.println("TestDefaultClass.printInfo");
}
}
------------------------------------------------------------------------------
//创建TestDefaultClass类对象,调用抽象方法printInfo()&默认方法moren();
TestDefaultClass tfs = new TestDefaultClass();
tfs.printInfo();
tfs.moren();
```
- 默认方法
- JAVA8 以后,我们也可以在接口中直接定义静态方法的实现。 这个静态方法直接从属
于接口(接口也是类,一种特殊的类),可以通过接口名调用。
如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类,
可以通过子类名直接调用。
```java
package com.company.testInterface;
/**
* 测试接口中的新特性(默认方法)&静态方法
*/
public interface TestDefault {
public void printInfo();
//默认方法
default void moren() {
System.out.println("测试默认方法");
System.out.println("TestDefault.moren");
// 普通默认方法调用静态方法,可行
testStatic();
}
//静态方法
static void testStatic() {
System.out.println("TestDefault.testStatic");
// 静态方法不能调用默认方法,不可行
// moren();
}
}
class TestDefaultClass implements TestDefault {
@Override
public void printInfo() {
System.out.println("TestDefaultClass.printInfo");
}
static void testStatic() {
System.out.println("TestDefaultClass.testStatic");
}
}
------------------------------------------------------------------------------
//接口静态方法测试类
package com.company.testInterface;
public class Test {
public static void main(String[] args) {
TestDefaultClass tdc = new TestDefaultClass();
tdc.printInfo();
//调用默认方法
tdc.moren();
//调用从属于接口的静态方法
TestDefault.testStatic();
//调用子类的testStatic静态方法
TestDefaultClass.testStatic();
}
}
```
### 接口的多继承
- 接口支持多继承,和类的继承类似,子接口 extends 父接口,会获得父接口中的一切。
![image-20220330112115349](面向对象.assets/image-20220330112115349.png)
```java
package com.company.testInterface;
public class TestMultipleInheritance {
public static void main(String[] args) {
CImpl c = new CImpl();
c.testA();
c.testB();
c.testC();
}
}
interface A {
void testA();
};
interface B {
void testB();
};
interface C extends A, B {
void testC();
};
class CImpl implements C {
@Override
public void testA() {
System.out.println("CImpl.testA");
}
@Override
public void testB() {
System.out.println("CImpl.testB");
}
@Override
public void testC() {
System.out.println("CImpl.testC");
}
}
```
### 字符串String类详解
- String是最常用的类,要掌握String类常见的方法,它底层实现也需要掌握好,不然在工作开发中很容易犯错。
- String:就是把一堆字符串起来,统一使用。
- String 类又称作**不可变字符序列**。
- String 位于 java.lang 包中,Java 程序默认导入 java.lang 包下的所有类。
- Java 字符串就是**Unicode字符序列**,例如字符串“Java”就是4个Unicode字符'J'、' a'、' v'、' a'组成的。
- Java 没有内置的字符串类型,而是在标准 Java 类库中提供了一个预定义的类String,每个用双引号括起来的字符串都是 String 类的一个实例。
```java
package com.company.oop;
public class TestString {
public static void main(String[] args) {
String s0 = null;
String s1 = "";
String s2 = "java";
String s3 = new String("java");
System.out.println(s1.length());
System.out.println(s2.length());
// 调用空字符串方法,会报空指针异常
// System.out.println(s0.length());
System.out.println("============字符串相等的问题============");
String g1 = "hello world";
String g2 = "hello world";
String g3 = new String("hello world");
System.out.println(g1 == g2);
System.out.println(g1 == g3);
System.out.println(g1.equals(g3));
}
}
```
### String类常用的方法
String类是我们最常使用的类。列出常用的方法,请大家熟悉。
>String类的常用方法列表
>
>| 常用方法 | 解释说明 |
>| :----------------------------------------------------------- | :----------------------------------------------------------- |
>| **[charAt](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#charAt-int-)**(int index) | 返回字符串中第index个字符 |
>| **[equals](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equals-java.lang.Object-)**([Object](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html) anObject) | 如果字符串与 other 相等,返回true;否则返回false |
>| **[equalsIgnoreCase](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#equalsIgnoreCase-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) anotherString) | 如果字符串与 other 相等(忽略大小写),则返回true,否则返回 false。 |
>| **[indexOf](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#indexOf-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) str) | 返回从头开始查找第一个子字符串 str 在字符串中的索引位置。如果未找到子字符串 str,则返回-1。 |
>| **[lastIndexOf](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#lastIndexOf-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) str) | 返回从末尾开始查找第一个子字符串 str 在字符串中的索引位置。如果未找到子字符串 str,则返回-1。 |
>| **[length](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#length--)**() | 返回字符串的长度 |
>| **[replace](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#replace-char-char-)**(char oldChar, char newChar) | 返回一个新串,它是通过用newChar替换此字符串中出现的所有 oldChar 而生成的。 |
>| **[startsWith](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#startsWith-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) prefix) | 如果字符串以prefix开始,则返回true。 |
>| **[endsWith](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#endsWith-java.lang.String-)**([String](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html) suffix) | 如果字符串以prefix结尾,则返回true, |
>| **[substring](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#substring-int-)**(int beginIndex) | 返回一个新字符串,该串包含从原始字符串beginlndex到串尾。 |
>| **[substring](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#substring-int-int-)**(int beginIndex, int endIndex) | 返回一个新字符串,该串包含从原始字符串beginlndex到串尾或endIndex-1的所有字符。 |
>| **[toLowerCase](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toLowerCase--)**() | 返回一个新字符串,该串将原始字符串中的所有大写改成小写字母。 |
>| **[toUpperCase](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#toUpperCase--)**() | 返回一个新字符串,该串将原始字符串中的所有小写改成大写字母。 |
>| **[trim](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#trim--)**() | 返回一个新字符串,该串删除了原始字符串头部和尾部的空格。 |
>
>
### 内部类
- 我们把一个类放在另一个类的内部定义,称为内部类(inner class)
![image-20220330164529828](面向对象.assets/image-20220330164529828.png)
> 内部类的两个要点:
- 内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
- 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。
> 注意
- 内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类.编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。
- 非静态内部类
- **非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)**
- 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类
对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对
象。
- 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类
成员。
- 非静态内部类不能有静态方法、静态属性和静态初始化块。
- 成员变量访问要点:
- 1.内部类属性:this.变量名。
- 2.外部类属性:外部类名.this.变量名。
- 内部类的访问
- 1.外部类中定义内部类:new Inner()。
- 2.外部类以外的地方使用非静态内部类:Outer.Inner varname new Outer().new Inner()
- ```java
/**
*测试非静态内部类
*/
package com.company.innerClass;
//测试内部类的用法
public class Outer {
private int age = 10;
public void show(){
System.out.println("Outer.show");
System.out.println(age);
//外部类中定义内部类:
Inner i = new Inner();
System.out.println(i.age);
}
public class Inner{
int age = 20;
public void show(){
System.out.println("Innner.show");
System.out.println(age);
System.out.println(Outer.this.age);
Outer.this.show();
}
}
}
//测试类
package com.company.innerClass;
public class TestOuter {
public static void main(String[] args) {
Outer o = new Outer();
//外部类以外的地方使用非静态内部类:Outer.Inner varname = new Outer().new Inner().
Outer.Inner i = new Outer().new Inner();
i.show();
}
}
```
- 静态内部类
- 定义方式
static class ClassName{
//实体
}
- 使用要点:
- 静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。
- 静态内部类看做外部类的一个静态成员。
```java
package com.company.innerClass;
/**
* 测试静态内部类
*/
class Outer2 {
private int a= 10;
private static int b= 20;
/**
*相当于外部类的一个静态成员
*/
static class Inner2{
public void test(){
// System.out.println(a); 静态内部类不能访问外部类的普通成员。
//静态内部类可以访问外部类的静态成员
System.out.println(b);
}
}
}
/**
* @author lishuai
*/
public class TestStaticInnerClass{
public static void main(String[] args) {
//通过new 外部类名.内部类名()来创建内部类对象
Outer2.Inner2 i2 = new Outer2.Inner2();
i2.test();
}
}
```
- 匿名内部类
- 适合那种只需要使用一次的类。比如:键盘监听操作等等。在安卓开发、awt、swing开发中常见。
- 语法
new 父类构造器(实参类表)\实现接口(){
//匿名内部类类体!
}
```java
package com.company.innerClass;
/**
* 测试匿名内部类
*/
public class TestAnonymousInnerClass {
public void test1(A a) {
a.run();
}
public static void main(String[] args) {
TestAnonymousInnerClass t = new TestAnonymousInnerClass();
t.test1(new A() {
@Override
public void run() {
System.out.println("第一个匿名内部类");
}
});
t.test1(new A() {
@Override
public void run() {
System.out.println("第二个匿名内部类");
}
});
}
}
interface A {
void run();
}
```
- 局部内部类
- 定义在方法内部的,作用域只限于本方法,称为局部内部类。
- 局部内部类在实际开发中应用很少。
```java
package com.company.innerClass;
/**
* 测试局部内部类
*/
class TestLocalInnerClass {
public void show(){
//作用域仅限于该方法
class Inner{
public void fun(){
System.out.println("Inner.show");
}
}
new Inner().fun();
}
public static void main(String[] args) {
TestLocalInnerClass tlic = new TestLocalInnerClass();
tlic.show();
}
}
```