2021.7.10
1.面向过程&面向对象
- 面向过程的思想
- 步骤清晰简单,第一步做什么,第二部做什么
- 面向过程适合处理一些较为简单的问题
- 面向对象思想
- 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行独立思考。最后,才对某个分类下的细节进行面向过程的思索。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题
- 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到围观操作,任然需要面向过程的思路去处理
2.面向对象
- 面向对象编程(Object-Oriented Programming,OOP)
- 面向对象编程的本质就是:以类的方式组织代码,以对象来组织(封装)数据
- 抽象:可以理解为将具体的东西用代码抽象来描述
- 三大特效
- 封装
- 继承
- 多态
- 从认识角度考虑是先有对象后有类。对象,是具体的事物。类是抽象的,是的对象的抽象描述
- 从代码运行角度考虑是现有类后有对象。类是对象的模板。
3.回顾方法的调用
静态方法和非静态方法,静态方法就是使用了Static修饰的
-
静态方法,当一个类中的方法使用static来修饰,就是静态方法,在其他的类中被调用的时候,直接使用类名.方法名就可以直接调用。
-
非静态方法:使用上述的调用方法调用非静态方法是非法的,需要先实例化一个对象,然后通过对象来调用次方法。例如:
Student S = new Student(); S.方法//直接调用
总之,若要调用一个类的静态方法,需要先实例化一个对象,然后通过兑现过来调用此方法
4.类与对象的关系
- 类是一种抽象出来的数据类型,它是对某一事物的整体描述/定义,但是不能代表某一个具体的事物
- 动物类、植物类、手机类、电脑类;
- 对象是抽象概念的具体实例
- 某张三、某旺财等
5.构造器(构造方法)
-
类中的构造器也成为构造方法,是进行创建对象的时候必须要调用的。
-
构造器的特点
- 必须和类的名字相同
- 必须咩有返回值,也不能写void
- 一个类及时什么都不写,它也会自然而然的构造一个构造器;
-
构造器的作用
-
构造方法一般用于初始化值;例如在构造方法中可以:
public class Demo{ String name; publlic Demo(){//构造方法 This.name = "zhongguo" } }
this就是指Demo的对象,当new一个对象的时候,其本质还是在调用构造方法,接下来调用的时候:
public class Application { public static void main(String[] args) { Demo d = new Demo(); System.out.println(d.name);//输出“zhongguo”; } }
-
构造方法重载:当一个构造方法定义成为一个有参构造方法时,类构造器的无参构造方法就必须单独再显示定义,否则会报错;具体如下:
public class Demo{ String name; publlic Demo(){//无参的显式定义,若此方法不写,调用时非法 } publlic Demo(String name){//有参构造器,形式参数name,并非第二行的name属性 This.name = name; } }
-
快捷键:alt+insert会生成构造器,弹出窗口选择:constructor,然后不选择成员直接回车就是无参的构造器;
-
-
总结:
- 构造器和类名相同,没有返回值
- new的本质就是在调用构造器
- 构造器可以初始化初始值
- 如果使用无参构造,需要显式定义一个无参构造方法
6.封装
-
一个类中该藏起来的需要藏起来,限制用户的访问权限
- 程序设计追求“高内聚,低耦合”,
- 高内聚:就是内部的而数据操作细节由自己完成,不允许外部干涉;
- 低耦合:仅暴露少量的方法供外部使用
- 程序设计追求“高内聚,低耦合”,
-
封装
- 信息的隐藏
-
封装属于私有,深入理解get/set,get/set就是提供操作类里面一些属性的方法
-
下面举例:
public class Student { private String name;//对成员进行保护 private int age; private String id; private char gender; public void setName(String name) {//给数据赋值 this.name = name; } public String getName() {//取出赋值后的数据、下同 return this.name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
public class Application { public static void main(String[] args) { Student s1 = new Student(); s1.setName("彭于晏"); //给数据赋值 System.out.println(s1.getName());//取出值 s1.setAge(30); System.out.println(s1.getAge()); } }
-
封装的意义:
-
使得类里面的数据得到很好的保护,提高程序安全性
-
隐藏类里面实现的细节
-
增强了程序的可维护性,良好的封装便于改写程序的内部代码,例如在set方法中,可以加入一些约束条件,判断用户调用的时候时候是否合法安全:例如:
public void setAge(int age) { if(age >120 || age <0){ System.out.println("年龄不合法"); }else { this.age = age; } }
-
统一了接口(get/set)
-
-
快捷键alt+insert,然后找到get或者set后可以快速生成get/set方法
7.继承
- 继承的本质就是对某一批类的抽象,从而实现对世界更好的建模
- extends的意思就是扩展。子类是父类的扩展
- Java中类只有单继承,没有多继承
- 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等
- 继承关系的两个类,一个为子类,一个为父类,子类继承父类,使用关键字extends
- 子类和父类之间,从意义上讲应具有“is a”的关系
- 子类可以继承父类的所有public方法和公有属性,当父类的属性使用private或者protacted
- 快捷键ctrl+h,调出继承树,发现父类会继承一个叫做Object的类,在Java中,所有的类,都会默认或者直接继承一个叫做Object的类
8.super详解
-
super和this关键字的区别
-
this指的就是当前所在的类,可以想象成当前类的一个实例化对象
-
super是指当前类的父类,可以当做父类的实例化对象
-
当父类的方法是私有时,super不能调用父类的私有方法
-
当在第三方类中实例化子类时,会默认首先调用父类的构造方法,然后调用子类的构造方法:
public class Person { public Person() { System.out.println("父类构造器"); } }
public class Student01 extends Person{ public Student01() { System.out.println("子类构造器"); } }
public class Application { public static void main(String[] args) { Student01 s = new Student01(); } }
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l2A7CDjR-1626246744857)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210712154651893.png)]
-
并且,调用父类的无参构造方法(auper.xxx)必须放在第一行(如果要显式调用super的话),this.xxx也一样,如果super.XXX和this.XXX在同一个地方显式调用的话可能会报错,即不能同时调用;
-
9.方法的重写
-
重写都是方法的重写,和属性无关
-
当父类和子类的方法属于静态方法时,父类的引用可以指向子类,下面代码中, B extends A,test()方法都使用static修饰:
public class A { public static void test(){ System.out.println("A"); } }
public class B extends A{ public static void test(){ System.out.println("B"); } }
public class Application { public static void main(String[] args) { B b = new B(); b.test(); A a = new B();//父类的引用a指向子类B a.test();//调用的依旧是A中的test() } }
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vmf07MQh-1626246744862)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210712163340114.png)]
-
重写
-
当父类和子类的方法是非静态方法时,方法名字一样时就是重写了,且修饰符应该是public
public class A { public void test(){ System.out.println("A"); } }
public class B extends A{ @Override public void test() {//子类重写了父类的test() System.out.println("B"); } }
public class Application { public static void main(String[] args) { B b = new B(); b.test(); A a = new B();//父类的引用a指向子类B a.test();//因为子类B重写了A的test方法,输出B,因此重写后调用的是B里面的重写方法 } }
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nNUJ2X8m-1626246744870)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210712163624634.png)]
-
重写只针对于子类和父类的
-
-
需要有继承关系才能重写,而且是子类重写父类的方法
-
方法名必须相同并且是public方法
-
修饰符的范围只能扩大:即子类重写的方法的范围(即修饰符)要大于父类的范围,(public > protected > default > private)
-
抛出的异常是相反的,即抛出的异常的范围必须是缩小的,不能扩大:
重写异常抛出范围不能大于父类
-
记住快捷键:alt+insert 然后选中Override
-
为什么需要重写?
- 子类不一定需要或者不一定满足
9.多态
-
增强程序的可扩展性
-
即同一个方法可以根据发送对象的不同为采取多种不同的行为方式
-
一个对象的实际类型是确定的,但是可以指向对象的引用类型有很多
-
多态的存在条件:
-
有继承关系
public class A { public void test(){ System.out.println("A"); } }
public class B extends A{ }
-
子类重写父类方法
public class B extends A{ @Override public void test() { System.out.println("B"); } }
-
父类的引用指向子类对象
public class Application { public static void main(String[] args) { A a = new B();//父类的引用a指向了子类B a.test(); } }
*注意:*多态是方法的多态,属性没有多态性,
static方法属于类,不能重写
final是属于常量
private方法属于私有
-
10.instanceof和类型转换
-
instanceof:判断一个对象是什么类型,判断两个类是否有父子关系
X instenceof Y
意义就是判断X指向的类型或者X对象跟Y是不是有父子关系;有就会返回true,没有就会返回false,包括“子孙关系”;
-
对象类型的强制转换
当一个父类的引用(对象)指向了一个子类(Person person = new Student(),Person是Student的父类),同时需要用父类的引用来调用子类中的没有被重写的方法时,是不能直接调用的,需要强制转换为子类的引用才能对子类中的方法进行调用。强制转换的语法:((子类)父类对象),调用子类的方法时,就可以使用((子类)父类对象).XX()来实现,父转子,也就是乡下强制转
例如:
public class Person { }
public class Student01 extends Person{ public void go(){ System.out.println("子类的方法"); } }
public class Application { public static void main(String[] args) { Person person = new Student01();//指向子类的引用person ((Student01)person).go();//将父类引用person强制转换为Student类的引用 } }
11.static小结
-
修饰成员属性或者成员方法时,称之为静态属性或者静态方法
-
调用静态成员或者静态方法时,可以使用类来直接调用,比如;
public class Application { private static int age; private int score; public static void say(){ System.out.println("静态方法"); } public void go(){ System.out.println("非静态方法"); } public static void main(String[] args) { Application a = new Application(); System.out.println(Application.age);//静态属性age可以直接通过类就可以访问 Application.say();//静态方法say()可以直接通过类就可以访问 System.out.println(a.score);//非静态属性需要用对象a进行访问 a.go();//非静态方法需要用对象a进行访问 } }
-
静态代码快、静态构造方法、匿名构造方法的加载顺序问题
public class Demo { public static void main(String[] args) { Demo demo1 = new Demo(); //System.out.println("==============="); //Demo demo2 = new Demo(); } { System.out.println("匿名代码快"); } static { System.out.println("匿名代码块"); } public Demo() { System.out.println("构造方法"); } }
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9bqPPcs-1626246744874)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210713003227689.png)]
当再次实例化一个对象执行时候;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLgnrDaw-1626246744877)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210713003816259.png)]
结论:静态代码块是最先加载的,反而构造器的加载排在最后,再次初始化一个类的时候,静态方法不再加载了,说明,静态方法只会执行一次;
12.抽象类
-
abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。
-
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
-
抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
-
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
public abstract void test();
-
子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。也就是说子类一定要重写抽象父类中的抽象方法;除非子类也是一个抽象类
public abstract class Demo02 {//抽象类 public abstract void test();//抽象方法 }
public class Demo03 extends Demo02 { @Override public void test() {//重写父类的抽象方法,否则报错 } }
-
抽象类只能是单继承
13.接口
-
普通类:只有具体实现
-
抽象类:具体实现和规范(抽象方法)都有!
-
接口:只有规范!
-
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是.….则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
-
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
-
OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
-
声明类的关键字是class,声明接口的关键字是interface
-
接口中的方法默认是抽象的;
-
接口都需要实现类,其实现类通过使用implements来初始化,命名规则一般是接口名字+Ipml,并且实现类需要重写接口里面的所有方法
-
可多继承
public interface Demo04 { //接口中的所有定义其实都是抽象的 public abstract void say(String name); void look(); public void run(); public void jump(); }
public interface Demo05 { void hello(); }
//实现类需要重写借口里面的方法,否则报错 public class DemoIpml implements Demo04,Demo05{//实现了多继承 @Override//实现类需要重写借口里面的方法 public void say(String name) { } //实现类需要重写借口里面的方法 @Override public void look() { } //实现类需要重写借口里面的方法 @Override public void run() { } //实现类需要重写借口里面的方法 @Override public void jump() { } //实现类需要重写借口里面的方法 @Override public void hello() { } }
-
接口的属性
-
在借口中定义的属性默认为常量,例如:
public interface Demo05 { public static final int age = 90;//其中,public static final都是默认的 }
-
14.内部类
-
内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
-
成员内部类
-
内部类可以访问外部内的属性和方法
-
如何实例化外部类和内部类?
public class Out {//外部类 private int age = 10; public void sayOut(){ System.out.println("外部方法"); } public class In{//内部类 public void sayIn(){ System.out.println("这是内部类"); } public int getAge(){//内部类访问外部类的私有变量 return age; } } }
public class Application01 { public static void main(String[] args) { Out out = new Out();//实例化一个外部类 Out.In in = out.new In();//初始化内部类; System.out.println(in.getAge()); } }
-
-
静态内部类:使用static修饰的内部类
public class Out {//外部类 private int age = 10; public void sayOut(){ System.out.println("外部方法"); } public static class In{//静态内部类 public void sayIn(){ System.out.println("这是内部类"); } } }
使用静态内部类之后,就无法访问外部类的非静态属性了,因为static总是在最前面实例化,外部非静态属性还没有初始化;
-
局部内部类
public class Out01 { private int age = 10; public void sayOut(){ class In{//局部内部类 public void sayIn(){ System.out.println("这是局部内部类"); } } } }
-
匿名内部类
一个Java类中可以多个class类,但是只能有一个public class类,不用讲实例保存到变量中;
public class Out {//外部类 private int age = 10; public void sayOut(){ new A().eat()//匿名内部类,不用讲实例保存到变量中 } } class A{ public void eat(){ System.out.println("HelloWorld"); } }