1.对象和类
1.1 对象和类的关系:对象是类的实例,类是对象的模板。
1.2 对象:拥有属性和方法
属性:静态特征,数据,变量
方法:动态特征,行为,功能
属性是数据,方法就是对数据的操作
1.3 面向对象:
对象:现实世界中的所有实体都是对象(万物皆对象)
类 : 对具有共同属性和行为的对象进行抽象,得到的一个抽象的概念
在面向对象编程时要追求低内聚,高耦合(模块越独立越好,模块间的关系越松散越好)
面向对象编程的特点和好处:面向对象更方便代码的修改,维护,扩展;数据和功能是一个整体
2.封装
2.1 什么是封装:
将类的某些信息隐藏在类内部,不允许外部程序直接访问,通过调用方法来实现对隐藏信息的操作和访向。
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
方法:封装操作
类:数据+对数据的操作
getter和setter方法:不能直接操作成员变量
2.2 如何使用封装:
使用访问修饰符
2.2.封装的好处:
将变化隔离;便于使用;提高重用性;安全性。
2.3 封装的格式:
1、使用访问修饰符修饰成员变量和成员方法
2、对外提供getter和setter方法
3.继承
3.1 什么是继承:
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
3.2 继承的优缺点:
优点 :
新的实现很容易,因为大部分是继承而来的
很容易修改和扩展已有的实现
缺点 :
打破了封装,因为基类向子类暴露了实现细节
白盒重用,因为基类的内部细节通常对子类是可见的
当父类的实现改变时可能要相应的对子类做出改变
不能在运行时改变由父类继承来的实现
由此可见,组合比继承具有更大的灵活性和更稳定的结构,一般情况下应该优先考虑组合。只
有当下列条件满足时才考虑使用继承:
子类是一种特殊的类型,而不只是父类的一个角色
子类的实例不需要变成另一个类的对象
子类扩展,而不是覆盖或者使父类的功能失效
3.3 继承的格式:
子类名 extends 父类名{ }
3.4 继承关系下代码的执行顺序
父类的静态代码块
子类的静态代码块
父类的构造代码块
父类的无参构造方法
子类的构造代码块
子类的无参构造方法
=============================
父类的构造代码块
父类的无参构造方法
子类的构造代码块
子类的有参构造方法
总结:1、优先调用父类
2、静态代码优先加载,且只加载一次(作用:第一个对象创建时,执行一些操作(记录日志:))
3、构造代码块每次调用构造方法时都会调用(作用:每一个该类创建时可以记录日志)
4、子类的构造方法不管有参无参都会先去调用父类的无参构造
1 //测试类 2 public class TestDemo{ 3 public static void main(String[] args) { 4 Son son =new Son(); 5 System.out.println("============================="); 6 Son son2 =new Son("name"); 7 } 8 } 9 //父类 10 class Father { 11 static { 12 System.out.println("父类的静态代码块"); 13 } 14 { 15 System.out.println("父类的构造代码块"); 16 } 17 public Father() { 18 System.out.println("父类的无参构造方法"); 19 } 20 public Father(String name) { 21 System.out.println("父类的有参构造方法"); 22 } 23 24 } 25 //子类 26 class Son extends Father { 27 static { 28 System.out.println("子类的静态代码块"); 29 } 30 { 31 System.out.println("子类的构造代码块"); 32 } 33 public Son() { 34 System.out.println("子类的无参构造方法"); 35 } 36 public Son(String name) { 37 System.out.println("子类的有参构造方法"); 38 } 39 40 } 41 //执行结果: 42 /*父类的静态代码块 43 子类的静态代码块 44 父类的构造代码块 45 父类的无参构造方法 46 子类的构造代码块 47 子类的无参构造方法 48 ============================= 49 父类的构造代码块 50 父类的无参构造方法 51 子类的构造代码块 52 子类的有参构造方法 53 */
4.构造方法
4.1 定义和作用
在Java中,任何变量在被使用前都必须先设置初值。Java提供的为类的成员变量赋初值的专门方法。(初始化变量)
4.2 常识:子类的所有构造方法都会去访问一次父类的无参构造方法
问题:为什么子类要去访问父类的构造方法?
解析:因为子类继承父类,会继承到父类中的数据,所以必须要看父类是如何对自己的数据进行初始化的。所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程。
问题:如果父类中没有无参的构造方法该怎么办?
分析:父类中没有无参构造,那么子类在初始化的时候就会报错。
解决办法:1、在父类中加一个无参构造方法
2、通过使用super关键字去显示的调用父类的带参构造方法
3、子类通过this去调用本类的其它构造方法(比如用子类的有参去调用自己的无参构造方法,但无参构造里一定要有super())
5.访问修饰符
5.1 访问修饰符使用范围
用来修饰成员变量和成员方法,不能用来修饰局部变量
5.2 访问修饰符权限
同类 同包 子类 其他包
private V X X X
默认 V V X X
protected V V V X
public V V V V
6.四个关键字
6.1 static(静态的)
使用范围:用来修饰成员变量、成员方法和代码块
作用 :
1.想要实现对象中的共性数据的对象共享。可以将这个数据进行静态修饰。
2.被静态修饰的成员,可以直接被类名所调用。
3.静态随着类的加载而加载。而且优先于对象存在。
命名方式:
属性(成员变量):
有static修饰:静态成员(静态变量)
没有static修饰:实例成员(非静态变量)(非静态成员)
方法(成员方法):
有static修饰:静态方法(静态方法)
没有static修饰:实例方法(非静态方法)(非静态方法)
代码块({ }) :
有static修饰:静态代码块
没有static修饰:非静态代码块(构造代码块)
总结 :
a.不管是静态方法还是非静态方法,都需要调用后执行,其执行的次序和在类里声明的次序无关,区别是静态方法是“class.method"方式执行,非静态方法是"object.method"方式执行,即后者需要创建一个对象。
b.静态成员变量(也称类变量)先于非静态成员变量初始化,静态成员变量在类第一次加载时初始化,所有对象共享一份静态成员变量,非静态成员变量则在对象创建时初始化
6.2 final(最终的)
使用范围:修饰类、修饰方法、修饰变量
作用:1、修饰的类不可被继承
2、修饰的方法不能被重写
3、修饰的变量的值不能更改(即为常量,通常变量名全大写)
作用(详细):
1、被final修饰的类不能被继承
2、被final修饰的成员变量
a. 必须初始化值。
b. 被fianl修饰的成员变量赋值,有两种方式:1、直接赋值 2、全部在构造方法中赋初值。
c. 如果修饰的成员变量是基本类型,则表示这个变量的值不能改变。
d. 如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变的。
3、被final修饰的方法不能被重写
a. 一个类的private方法会隐式的被指定为final方法。
b. 如果父类中有final修饰的方法,那么子类不能去重写。
6.3 this和super
两者定义的区别:
this代表本类的引用
super代表父类存储空间的标识(可以理解为父类的引用,可以操作父类的成员)
两者使用的区别:
调用成员变量:
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
调用构造方法:
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
调用成员方法:
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
7.方法的相互调用
静态方法是“class.method"方式执行,非静态方法是"object.method"方式执行,即后者需要创建一个对象。
7.1 同类 :
静态调用静态
a.直接调
b.类名.方法名
c.对象名.方法名(不建议使用,因为这样不能分辨是静态调静态还是静态调非静态)
静态调用非静态
创建调用类的对象,再对象名.方法名
非静态调用静态
a.直接调用
b.类名.方法名
c.对象名.方法名(不建议使用)
非静态调用非静态
a.直接调用
b.对象名.方法名
7.2 不同类
静态调用静态
类名.方法名
静态调用非静态
创建调用类的对象,再对象名.方法名
非静态调用静态
类名.方法名
非静态调用非静态
对象名.方法名
8.方法的重载
同一个类中,方法名相同,参数的数量,类型,顺序不同即为重载(只与参数有关)
9.方法的重写
发生在继承关系下,子类对父类允许访问的方法的实现过程进行重新编写, 方法签名相同(即返回值和形参都不能改变。即外壳不变,核心重写)
细节题:要答全面
10.局部变量和成员变量的区别
内存空间:
局部变量:栈
成员变量:数据存储在堆中,栈中存储堆空间的地址
初始值:
局部变量:没有初始默认值
成员变量:有初始默认值
作用域:
局部变量:声明的有效的代码块范围使用
成员变量:类中都能使用
11.类中定义的静态成员变量和非静态成员变量的区别
静态成员变量 :属于类,无论创建多少对象,内存中只有一个 调用方法:类.静态成员变量
非静态成员变量:属于对象,每次创建一个对象都会分配独立的存储空间 调用方法:对象.非静态成员变量
12.列举抽象类和抽象方法的相关语法
a.抽象方法只有定义,没有实现
b.抽象方法所在的类必须是抽象类
c.抽象类中可以不定义抽象方法
d.子类继承抽象类必须实现抽象类的抽象方法
13.多态
13.1什么是多态
解释a.同一对象,调用相同的方法,执行不同的操作。
解释b.同一引用类型,使用不同的实例执行不同的方法。
13.2多态的优缺点
优点:
提高了代码的扩展性,前期定义的代码可以使用后期的内容。
缺点:
前期定义的内容不能使用(调用)后期子类的特有内容。
13.3 多态的应用
a.使用父类类型作为方法的参数
b.使用父类类型作为方法的返回值
13.4 多态的实现步骤
1、子类重写父类的方法
2、程序运行时,子类对象赋给父类(向上转型)(Object obj = new Dog();)
3、通过父类对象调用方法,执行的是子类的方法
13.5 多态的表现形式
向上转型:子类转向父类
向下转型:父类转向子类
绑定方法:
1.如果是非抽象类,则通过父类名 引用名 = new 子类名();然后使用instanceOf关键字来检查左边的对象是否为右边的实例;
如果是抽象类,则通过抽象类名 引用名 = new 实现类名();
2.使用instance0关键字来检查左边的对象是否为右边的实例;
Father f = new Son();
if(f instanceof Son) {
((Son) f).run();//确认左边的对象是右边的实例后则可以调用方法
}
向下转型会遇到的异常:
在继承关系下著名的异常:java.lang.ClassCastException(类型转换异常) 父类Animal有两个子类Cat和Dog 向下转型 Animal a = new Cat; 强制转换 Cat c2 =(Cat)a; 可以调用猫的方法c2.catchMouse(); 但是 Animal b = new Dog; 强制转换 Cat c3 =(Cat)b; 此时编译是可以通过的 但是运行就会报错,因为狗和猫没有继 承关系
举例:a.使用父类类型作为方法的参数
1 //父类Pet 2 public class Pet { 3 public void eat() { 4 System.out.println("动物吃东西"); 5 } 6 7 } 8 //子类Dog 9 public class Dog extends Pet { 10 public void eat() { 11 System.out.println("狗吃肉"); 12 } 13 14 } 15 //子类Cat 16 public class Cat extends Pet { 17 public void eat() { 18 System.out.println("猫吃鱼"); 19 } 20 21 } 22 //主人 23 public class Master { 24 public void feed(Pet pet) {//直接让父类做形参,将子类对象的地址值赋值给父类 25 //变量,这样调用的就是子类的方法,因为编译器只认地址,地址是子类的就调用子类 26 //的方法 27 pet.eat(); 28 } 29 30 } 31 //测试类 32 33 public class TestDemo { 34 public static void main(String[] args) { 35 Master ma = new Master(); 36 ma.feed(new Dog()); 37 ma.feed(new Cat()); 38 39 } 40 } 41 //执行结果 42 狗吃肉 43 猫吃鱼
举例:b.使用父类类型作为方法的返回值
//简单工厂模式 :
缺点:破坏了开闭原则,但是以后的学习可以通过反射+配置文件重构代码
/* 结构的组成: 一个抽象产品(父类) 若干个实体产品(子类) 简单工厂:一个静态方法,返回值是父类对象 测试类:调用时,只需要知道父类和工厂,无需关注具体的子类 */ /* 简单工厂: 产品 抽象产品Car 实体产品Benz BMW 工厂 生产产品 缺点:破坏开闭原则,以后可以通过反射+配置文件重构代码 23个经典的设计模式中没有简单工厂 */ //抽象产品Car public class Car { public void run() { } } //实体产品 public class BMW extends Car { public void run() { System.out.println("BMW run"); } } public class Benz extends Car { public void run() { System.out.println("Benz run"); } } //工厂 public class Factory { public static Car createCar(String type) { Car car = null; switch (type) { case "BMW": car = new BMW(); break; case "Benz": car = new Benz(); break; default: break; } return car; } } //测试类 public class TestDemo { public static void main(String[] args) { System.out.println("先生你要买什么"); Scanner sc = new Scanner(System.in); Factory.createCar(sc.next()).run(); } }
23中设计模式中最简单的单例模式:
无论引用多少次对象,内存中只分配一个
1 public class MySingle { 2 // 无论引用多少次对象,内存中只分配一个对象 3 static MySingle mySingle; 4 5 private MySingle() {//私有化构造方法 6 7 } 8 9 public static MySingle getSingle() {//要是静态的不然不能调用方法 10 if (mySingle == null) { 11 mySingle = new MySingle(); 12 } 13 return mySingle; //返回实例对象 14 } 15 } 16 17 18 public class MySingleTest { 19 20 public static void main(String[] args) { 21 22 System.out.println(MySingle.getSingle()); 23 } 24 25 }