面向过程思想
面向对象思想
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
面向对象编程(Object-Oriented Programming,OOP)
面向对象编程的本质是:以类的方式组织代码,以对象的组织(封装)数据
抽象:白话理解就是抽像,把像的的抽取出来,具体的理解还是抽像
三大特征:
从认识论角度考虑是先有对象后有类。对象,是具体是事物,类,是抽象的,是对对象的抽象
从代码运行角度考虑是先有类后有对象。类是对象的模板
这些看不懂没关系,后面慢慢的就会恍然大悟!
? 一个真正的程序里面只有一个main方法,并不会像我们测试的时候每个类里面都有,我们只是为了方便代码的运行
回顾方法的定义
修饰符
返回类型
break和return的区别
方法名
参数列表
package com.xiaodi.operator.oop.demo01;//Demo01 类public class Demo01 { //main 方法 public static void main(String[] args) { } /* 方法的定义: 修饰符 返回值类型 方法名(...) { //方法体 return 返回值; } */ public String sayHello() { return "Hello,World"; } public double max(double a, double b) { return a > b ? a : b; //三元运算符 }}回顾方法的调用
静态方法
package com.xiaodi.operator.oop.demo01;//学生类public class Sudent { //静态方法 static public static void say() { System.out.println("学生说话"); }}package com.xiaodi.operator.oop.demo01;public class Demo02 { public static void main(String[] args) { //静态方法调用:类名.方法名; Sudent.say(); }}非静态方法
package com.xiaodi.operator.oop.demo01;//学生类public class Sudent { //非静态方法 public void say() { System.out.println("学生说话"); }}package com.xiaodi.operator.oop.demo01;public class Demo02 { public static void main(String[] args) { //非静态方法调用 //先实例化这个类 new ;对象类型 对象名 = new 对象值; Sudent sudent = new Sudent(); //然后调用 sudent.say(); }}特殊情况 原因:static 是和类一起加载的,这个类存在的时候它就存在,时间片非常早;普通方法是类实例化后才存在的
package com.xiaodi.operator.oop.demo01;public class Demo02 { public static void main(String[] args) {} //两个普通方法(非静态):可以直接相互调用,无需实例化 public void a() { b(); } public void b() {} public static void c() { d(); } public static void d() {}}package com.xiaodi.operator.oop.demo01;public class Demo02 { public static void main(String[] args) {} public static void a() { Demo02 demo02 = new Demo02(); demo02.b(); } public void b() {}}形参和实参:形式参数和实际参数的类型要对应
package com.xiaodi.operator.oop.demo01;public class Demo03 { public static void main(String[] args) { } public int add(int a, int b) { return a+b; }}package com.xiaodi.operator.oop.demo01;public class Demo03 { public static void main(String[] args) { Demo03 demo03 = new Demo03(); demo03.add(1,2); } public int add(int a, int b) { return a+b; }}值传递和引用传递
值传递引用传递的概念
package com.xiaodi.operator.oop.demo01;//值传递public class Demo04 { public static void main(String[] args) { int a = 1; System.out.println(a); //1 Demo04.change(a); System.out.println(a); //1 } //返回值为空 public static void change(int a) { a = 10; }}package com.xiaodi.operator.oop.demo01;//引用传递:java本质还是值传递public class Demo05 { public static void main(String[] args) { Perosn perosn = new Perosn(); System.out.println(perosn.name);//nell Demo05.change(perosn); System.out.println(perosn.name);//晓迪 } public static void change(Perosn perosn) { perosn.name = "晓迪"; }}//定义了一个Perosn类,有一个属性:nameclass Perosn { String name;//null}值传递和引用传递的理解
java本质还是值传递(为什么这么说:引用传递是里面存的首地址的copy。原来引用变量里的的对象你不能改,但是他指向的堆对象你可以改啊。)
结论:
上面还写了一个class(剧透了内部类的内容(后面会讲)) 一个类里面只能有一个public class 但是能有多个class
值传递和引用传递大家肯定觉得很绕,这是因为我们对 对象和从内存分析的理解还不透彻,本章后面后面的内容学完再来看一遍,肯定会恍然大悟!
类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但并不能代表某一个具体的事物
如动物、植物、手机、电脑
Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为
对象是抽象概念的具体实例
以后我们就不要在每一个类里面都去加上main方法,一个程序只有一个主启动类
一个项目只存在一个main方法
我们新建一个包,先来一个Student类,再来一个Application类,Application类定义一个main方法就好也是唯一的一个入口。
我们再IDEA上面,把Application类列到一边,方便我们随时进行测试,如图下

使用new关键字创建对象
package com.xiaodi.operator.oop.demo01.demo02;//学生类public class Student { //不管再厉害的人写的类里面只可能存在两个东西,1就是属性 2就是方法 //属性:可以理解为字段 String name; int age; //方法 public void study() { //this.代表当前这个类的 System.out.println(this.name+"在学习"); }}这样我们一个简单的类就定义出来了
package com.xiaodi.operator.oop.demo01.demo02;//一个项目应该只存在一个main方法public class Application { public static void main(String[] args) { //类是抽象的,我们需要把这个类实例化 //类实例化后会返回一个自己的对象! //student对象就是一个Student类的具体实例! Student student = new Student(); Student xiaoming = new Student(); Student xiaohong = new Student(); //类是抽象的可以这么理解:类就相当一个模板,没有具体的值 xiaoming.name = "小明"; xiaoming.age = 17; System.out.println(xiaoming.name); System.out.println(xiaoming.age); System.out.println(xiaohong.name);//默认值null System.out.println(xiaohong.age);//默认值0 //由此可见,同一个类new过来的对象是互不影响的,是一个具体的实例 }}Student类就是一个抽象的模板,然后我们通过new关键字,可以创建不一样的具体的实例!
大家现在再品一下这句话:以类的方式组织代码,以对象的组织(封装)数据,是不是恍然大悟!
使用new关键字创建的时候,除了分配内存空间之外,还会给 创建好的对象 进行默认的初始化 以及对类中构造器的调用
package com.xiaodi.operator.oop.demo01.demo02;public class Person { }package com.xiaodi.operator.oop.demo01.demo02;//一个项目应该只存在一个main方法public class Application { public static void main(String[] args) { Person person = new Person(); }}Person这个类里面我们没有写方法,但是还是能new一个实例出来,就证明类里面有一些默认的东西
这个对象是怎么来的,为什么能凭空new出来,我们去看这个Person类生成的class文件
我们在IDEA点开项目架构,选择modules,再选择新增一个目录(Add Content Root),选择我们的out目录,找到对应的class文件打开就行(如果没有对应的class文件,在IDEA运行一下文件就会生成) Person.class文件内容如下:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//package com.xiaodi.operator.oop.demo01.demo02;public class Person { public Person() { }}你会发现默认的帮我们加了一个方法,而且这个方法没有返回值,方法名字和类名相同;其实这就是一个构造器。
得出结论:一个类即使什么都不写,它也会存在一个方法
在.java文件显示的定义构造器:
package com.xiaodi.operator.oop.demo01.demo02;public class Person { public Person() { }}那么有人就会问,这个无参构造器能干什么:
package com.xiaodi.operator.oop.demo01.demo02;public class Person { //给我们初始化一些信息 String name; //作用 //1、使用new关键字,本质是在调用构造器 //2、用来初始化值 public Person() { this.name = "XiaoDi"; } //有参构造:一旦定义了有参构造,无参构造就必须显示定义 public Person(String name) { this.name = name; } //快捷键:Alt+Insert ,选择Constructor能自动生成构造器,参数能选}package com.xiaodi.operator.oop.demo01.demo02;//一个项目应该只存在一个main方法public class Application { public static void main(String[] args) { //我们可以重载很多个构造器,使用new实例化一个对象的时候,他会根据你传的参数来判断你调用的是哪个构造器 Person person = new Person(); Person person1 = new Person("XiaoDi"); System.out.println(person.name);//null System.out.println(person1.name);//XiaoDi }}构造器总结:
? 构造器定义需注意:
? 构造器的作用:
? 注意点:
? 快捷键:
构造器必须要掌握
1、类与对象
2、方法
3、对象的引用
引用类型、基本类型(8)
对象是通过引用来操作的
4、属性:也叫字段(Field)、或成员变量
? 默认初始化:
? 数字:0、0.0;
? char:u0000(转化为int类型输出0);
? boolean:false;
? 引用:null
? 属性的定义:修饰符 属性类型 属性名 = 属性值;
5、对象的创建和使用
6、类
听不懂没关系上代码:
package com.xiaodi.operator.oop.demo03;//学生类public class Student { //私有属性 private:私有 private String name; //名字 private int age; //年龄 private int id; //学号 private char sex; //性别 //提供一些可以操作这个属性的方法! //提供一些public 的 get、set方法 //get 获取这个数据 public String getName() { return this.name; } //set 给这个数据设置值 public void setName(String name) { this.name = name; } //记住Alt+Insert快捷键然后选择Getter 或者Setter 或者Getter and Serter然后能选择私有属性进行快速生成 //有人就会问了,封装有啥子用(可以避免用户去破坏这个系统,输入一些注入漏洞代码 或 输入一些不符合实际的东西) public int getAge() { return age; } public void setAge(int age) { if (age > 120 || age < 0) { //不合法 this.age = 3; }else { this.age = age; } }}package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo03.Student;public class Application { public static void main(String[] args) { Student s1 = new Student(); //当属性加上private之后就变成私有了 //是不能像原来那样调用的;原来那样调用是因为属性是public公共的。 //s1.name = "xiaodi"; 这样是会报红的 //通过类中公共方法调用、和修改 //get 访问 String name = s1.getName(); //set 修改 s1.setName("晓迪"); //输出看一下 System.out.println(s1.getName()); //封装的作用 s1.setAge(999); System.out.println(s1.getAge());//不符合就表示用户连基本的尝试都没有估计是个儿童,直接定义为3岁即可 }}总结->封装的意义:
作用在什么地方:这就要通过大家平时多写代码去积累经验了,大家现在还只是学会了这样一个操作,不知道什么地方需要使用到,在我们后面的学习中就会经常去写封装这个东西,大家到时候慢慢积累就行。
聊一聊方法重载:比如我们的println,为什么它啥都能输出,就是因为它重载了很多方法,方法的参数定义的不同,实现不同类型的输出;大家可以在IDEA中按住Ctrl键然后点击println进去看一下
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
extends的意思是“扩展”。子类是父类的扩展。
Java中类只有单继承,没有多继承! (可以理解为一个儿子只能有一个爸爸,一个爸爸能有多个儿子)
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合,聚合等
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示
子类和父类之间,从意义上讲应该具有“is a”的关系。(比如:Wangcai is a dog )
上代码理解:
Person 人 父类
package com.xiaodi.operator.oop.demo04;//Person 人 : 父类public class Person { //public 公共的,子类能继承 //protected 受保护的 //default 不写,默认 //private 私有的,子类不能继承;一般属性才会是私有的 public int money = 10_0000; //公共的 private int money1 = 10_0000_0000; //私有的,子类就不能继承,但是可以通过封装思想,留一些可以使用这些钱的方法 public void say() { System.out.println("说话"); } public int getMoney1() { return money1; } public void setMoney1(int money1) { this.money1 = money1; }}Student 学生 子类
package com.xiaodi.operator.oop.demo04;//学生也是人 所以继承人 :派生类或子类public class Student extends Person { //子类可以继承父类的所有方法、以及属性;}Application 启动方法(测试)
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo04.Student;public class Application { public static void main(String[] args) { Student student = new Student(); System.out.println(student.money); //父类的属性 (public) student.say(); //父类的方法(public) // System.out.println(student.money1); // (private)私有的不能继承,但是可以通过 父类给我留的方法去使用 System.out.println(student.getMoney1()); }}继承小总结:
记住一个快捷键Ctrl+H:查看当前继承的继承情况
当我们Person类什么都不写的情况下,new一个Person对象,然后输入person.就能点出一些方法,但是我们什么都没定义这是为什么呢?
package com.xiaodi.operator.oop.demo04;//Person 人//在Java中,所有的类,都默认直接或者间接继承Objectpublic class Person /*extends Object*/{}package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo04.Person;public class Application { public static void main(String[] args) { Person person = new Person(); //person.(equals(),hashCode(),toString()......) }}? 父类:Person
package com.xiaodi.operator.oop.demo04;//Person 人public class Person /*extends Object*/{ //修饰符 protected 受保护的 protected String name = "晓迪"; public void print() { System.out.println("Person"); }}? 子类:Student
package com.xiaodi.operator.oop.demo04;//学生也是人 所以继承人 :派生类或子类public class Student extends Person { private String name = "小迪"; public void print() { System.out.println("Student"); } public void text(String name) { System.out.println(name);//方法里的name System.out.println(this.name);//当前类的name System.out.println(super.name);//父类的name } public void text1() { print();//这个是当前类的print this.print();//这个也是当前类的print(建议写法) super.print();//父类里的print }}? 启动程序(测试):Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo04.Student;public class Application { public static void main(String[] args) { Student student = new Student(); student.text("XiaoDi"); System.out.println();//换行符 student.text1(); }}输出结果:
? XiaoDi
? 小迪
? 晓迪
? Student
? Student
? Person
想一下如果new子类的时候构造器的执行顺序是怎么样的:
? 父类:Person
package com.xiaodi.operator.oop.demo04;//Person 人public class Person /*extends Object*/{ public Person() { System.out.println("Person无参构造执行了"); }}? 子类:Student
package com.xiaodi.operator.oop.demo04;//学生也是人 所以继承人 :派生类或子类public class Student extends Person { public Student() { super();//子类构造器隐藏代码,在构造器的第一行,这一行不写效果也是一样的 //this("xiaodi"); 我们要调用自己的有参构造this("xiaodi");,也需要放在第一行,否则报错,也就是说两者在同一个构造器里只能使用一个; System.out.println("Student无参构造执行了"); } public String name; public Student(String name) { this.name = name; }}? 启动程序(测试):Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo04.Student;public class Application { public static void main(String[] args) { Student student = new Student(); }}输出:
? Person无参构造执行了
? Student无参构造执行了
也就是说父类的无参构造器先执行了
那么假如我的父类里面没有无参构造器:
? 父类:Person
package com.xiaodi.operator.oop.demo04;//Person 人public class Person /*extends Object*/{ public String name; public Person(String name) { this.name = name; }}? 子类:Student
package com.xiaodi.operator.oop.demo04;//学生也是人 所以继承人 :派生类或子类public class Student extends Person { public Student() {//报错 System.out.println("Student无参构造执行了"); }}但是也不是没有办法,没有无参构造,那你显示的写出调用父类的有参构造就行了:
? 子类:Student
package com.xiaodi.operator.oop.demo04;//学生也是人 所以继承人 :派生类或子类public class Student extends Person { public Student() { super("小迪"); System.out.println("Student无参构造执行了"); }}super小总结:
? 父类:Person
package com.xiaodi.operator.oop.demo04;//Person 人public class Person /*extends Object*/{ public Person() { System.out.println("Person无参构造执行了"); } public String name;}? 子类:Student
package com.xiaodi.operator.oop.demo04;//学生也是人 所以继承人 :派生类或子类public class Student extends Person { public Student() {//报错 this(18); System.out.println("Student无参构造执行了"); } public int age; public Student(int age) { super(); this.age = age; }}? 如果要调用子类中的有参构造方法的话,且不影响代码,就能像上面这种方法写:调用子类有参构造的同时还调用了父类的无参构造,以上代码的执行顺序是:1父类无参构造、2age=18、3子类无参构造
super VS this
静态方法
? 父类:B
package com.xiaodi.operator.oop.demo04;//重写都是方法重写,和属性无关public class B { public static void test() { System.out.println("B->test()"); }}? 子类:A
package com.xiaodi.operator.oop.demo04;public class A extends B{ public static void test() { System.out.println("A->test()"); }}? 启动程序:Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo04.A;import com.xiaodi.operator.oop.demo04.B;public class Application { public static void main(String[] args) { A.test(); B.test(); }}输出:
? A->test()
? B->test()
非静态方法
? 父类:B
package com.xiaodi.operator.oop.demo04;//重写都是方法重写,和属性无关public class B { public void test() { System.out.println("B->test()"); }}? 子类:A
package com.xiaodi.operator.oop.demo04;public class A extends B{ //这里使用Alt+Insert快捷键生成重写选择 有Override的 //Override:重写 @Override //注解:有功能的注释!这个不用纠结我们后面会单独讲 public void test() { System.out.println("A->test()"); }}启动程序:Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo04.A;import com.xiaodi.operator.oop.demo04.B;public class Application { //静态方法和非静态方法区别很大! //静态方法:方法的调用只和左边定义的数据类型有关(这个不叫重写) //非静态方法:非静态(且修饰符只能是public):子类重写了父类的方法(这个才叫重写) public static void main(String[] args) { // A a = new A(); a.test(); //A //父类的引用指向了子类 B b = new A();//子类重写了父类的方法 b.test();//B }}方法重写小总结:
特点:
重写,子类的方法和父类必须要一致;方法体不同!
为什么要重写:
快捷键:Alt+Insert,然后选择override
即同一方法可以根据发送对象的不同而采用多种不同的行为方式
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
多态存在的条件
注意:多态是方法的多态,属性没有多态性
上代码:
? 父类:Person
package com.xiaodi.operator.oop.demo05;public class Person { public void run() { System.out.println("run"); }}? 子类:Student
package com.xiaodi.operator.oop.demo05;public class Student extends Person{ @Override public void run() { System.out.println("son"); } public void eat() { System.out.println("eat"); }}? 启动程序:Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo05.Person;import com.xiaodi.operator.oop.demo05.Student;public class Application { public static void main(String[] args) { //一个对象的实际类型是确定的 //new Student(); //new Person(); //可以指向的引用类型就不确定了 Student s1 = new Student(); Person s2 = new Student();//父类的引用指向子类 Object s3 = new Student(); //得出结论:一个类的实际对象类型是确定的,但是指向的引用类型可以是他的父类和Object类 //我们现在在Person类里写一个run方法,我们就能用s2去调用(输出run);然后我们去子类重写一下这个rum方法 s2.run(); s1.run(); //两个都输出son(也就是说如果子类重写了父类的方法,那么就执行子类的方法) //我们在子类加了一个eat方法(父类没有):那么s2还能去调用这个方法吗(s1肯定可以,因为s1就是Student类型) s1.eat(); //s2.eat(); 是不可以这样去调的(因为我们的s2是Person类型的,person里没有这个方法) //但是如果person里面和student里面都有的话,子类没有重写的情况下那么它就调用父类的,如果子类重写了那么就调用子类的 //得出结论:对象能执行哪些方法,主要看对象左边的类型,和右边关系不大 // Student(子类)类型能调用的方法都是自己的或者继承父类的 // Person(父类)类型,虽然可以指向子类,但是不能调用子类独有的方法 }}多态小总结:注意事项(一定要把注意事项搞明白我们才能避免错误的发生)
instanceof
instanceof:判断一个对象是什么类型(有父子关系就ok,没有就不行)
演示:
? 父类:Person
package com.xiaodi.operator.oop.demo05;public class Person { public void run() { System.out.println("run"); }}? 子类:Student
package com.xiaodi.operator.oop.demo05;public class Student extends Person{}? 子类:Teacher
package com.xiaodi.operator.oop.demo05;public class Teacher extends Person {}? 启动程序:Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo05.Person;import com.xiaodi.operator.oop.demo05.Student;import com.xiaodi.operator.oop.demo05.Teacher;public class Application { public static void main(String[] args) { //当前的关系:Opject > Person > Student //当前的关系:Opject > Person > Teacher Object object = new Student(); System.out.println(object instanceof Student);//ture System.out.println(object instanceof Person);//ture System.out.println(object instanceof Object);//ture System.out.println(object instanceof Teacher);//false System.out.println(object instanceof String);//false System.out.println("====================="); Person person = new Student(); System.out.println(person instanceof Student);//true System.out.println(person instanceof Person);//true System.out.println(person instanceof Object);//true System.out.println(person instanceof Teacher);//false // System.out.println(person instanceof String);//编译报错! System.out.println("====================="); Student student = new Student(); System.out.println(student instanceof Student);//true System.out.println(student instanceof Person);//true System.out.println(student instanceof Object);//true // System.out.println(student instanceof Teacher);//编译报错! // System.out.println(student instanceof String);//编译报错! }}得出结论:System.out.println(x instanceof y);
类型转换
? 父类:Person
package com.xiaodi.operator.oop.demo05;public class Person { public void run() { System.out.println("run"); }}? 子类:Student
package com.xiaodi.operator.oop.demo05;public class Student extends Person{ public void go() { System.out.println("go"); }}? 启动程序:Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo05.Person;import com.xiaodi.operator.oop.demo05.Student;public class Application { public static void main(String[] args) { //现在我们知道Student里面能用两个方法,一个是go,一个是继承过来的run //类型之间的转换 :父(高) 子(低) //低转高 (子类转换为父类:可能丢失自己本来的一些方法!) Student student = new Student(); Person ps = student; ps.run(); Person person = new Student(); //我们这边person.go();是会报错的,如果我们想让他执行就要进行类型转换 //高转低(强制转换)Person类型转换成Student类型 Student person1 = (Student) person; person1.go(); //和成一句代码就是象下面这样 ((Student) person).go(); }}多态总结:
这些大家可能会很懵,都是一些理论知识,每个人的理解能力不一样,知道怎么用就行,等后面用到了,你自然就懂了,后面自己慢慢悟,别着急!别着急!别着急!
static:加在属性上叫静态属性,加在方法上叫静态属性
package com.xiaodi.operator.oop.demo06;public class Student { private static int age; //静态属性 private double score; //非静态属性 public void run() {} //非静态方法 public static void go() {} //静态方法 public static void main(String[] args) { Student s1 = new Student(); System.out.println(Student.age);//通过类调用 System.out.println(age);//跟上面的效果一样 //System.out.println(score);//非静态属性会报错 System.out.println(s1.age);//通过对象调用 System.out.println(s1.score);//通过对象调用 Student.go(); go(); s1.go(); s1.run(); }}? 一个类里面的静态属性或方法在内存中是和类一起加载的,能通过类调用(在本类中甚至能直接写);非静态的则需要通过new
package com.xiaodi.operator.oop.demo06;public class Person { //匿名代码块 { System.out.println("匿名代码块"); } //静态代码块 static { System.out.println("静态代码块"); } //构造器 public Person() { System.out.println("构造方法"); } public static void main(String[] args) { Person person1 = new Person(); System.out.println(); Person person2 = new Person(); }}执行结果:
? 静态代码块
? 匿名代码块
? 构造方法
? 匿名代码块
? 构造方法
通过执行结果我们发现:静态代码块最优先,其次才是匿名代码块,最后才执行构造方法,且静态代码块只执行一次
匿名代码块我们一般用来赋一些初始值
package com.xiaodi.operator.oop.demo06;//import java.lang.Math.random; 导入java.lang下面的Math类下面的random方法,这样是会报错的,需要加上静态import static java.lang.Math.random;public class Test { public static void main(String[] args) { //生成随机数:Math.random System.out.println(Math.random()); //这样调用是不是很麻烦,我们把方法导进来 System.out.println(random());//导进来之后就能这样写 }}主要说一下:通过final修饰的类就不能被继承了(意思就是断子绝孙了哈哈哈)
abstract修饰符可以用来修饰方法也可以用来修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
? 父类:Action
package com.xiaodi.operator.oop.demo07;//abstract 抽象类public abstract class Action { //abstract 抽象方法,只有方法的名字,没有方法的实现 (约束,让别人帮我们实现) public abstract void doSomething(); //抽象类的特点: //不能new这个抽象类,只能靠子类去实现它:约束! //只能去new它的子类,如果它的子类没实现,只能去new它的子子类 //抽象类里面可以写普通方法 //抽象方法必须在抽象类中 //思考? // 抽象类既然不能new,那么存在构造器吗?(大家自己打开class编译看一下) // 抽象类存在的意义? (提高开发效率)}? 子类:A
package com.xiaodi.operator.oop.demo07;//抽象类的所有方法,继承它的子类,都必须要重写去实现他的方法,除非它的子类也是抽象类//抽象类extends:单继承,有局限性,(接口可以多继承)public class A extends Action{ @Override public void doSomething() { System.out.println("doSomething"); }}抽象类并不是我们的重点,了解一下就好了;下面的接口跟抽象类非常像用的人也比较多(接口可多继承)
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有! 业余约束!
接口:只有规范!自己无法写方法~专业的约束! 能干约束和实现分离:面向接口编程
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是...则必须能...”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你是好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
接口本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计 模式都只针对具备了抽象能力的语言(比如c++、java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
声明类的关键字是class,声明接口的关键字是interface
? 接口:UserService
package com.xiaodi.operator.oop.demo08;//interface 定义的关键字 接口都需要有实现类public interface UserService { //接口中的所有定义其实都是抽象的 //属性默认的是一个静态常量 public static final int age = 99; //一般不会这么玩 // public abstract void add(String name);//假设方法修饰符你不写默认就是public abstract //所以接口都可以像下面这样去写 返回值类型 方法的名字([参数可选]); void add(String name); void delete(String name); void update(String name); void query(String name);}? 接口:TimeService
package com.xiaodi.operator.oop.demo08;public interface TimeService { void timer();}? 接口的实现:UserServiceImpl
package com.xiaodi.operator.oop.demo08;//实现类名一般加一个Impl就行//implements 接口实现类关键字 (从侧面实现了我们的多继承)public class UserServiceImpl implements UserService,TimeService{ //如果你要去实现接口里面的所有定义,你必须要去重写里面的所有方法 @Override public void add(String name) { } @Override public void delete(String name) { } @Override public void update(String name) { } @Override public void query(String name) { } @Override public void timer() { }}接口的点作用:
? 抽象的思想很难锻炼 :Java谁都会对吧 那么为什么有些人能做到架构师有些人不能 (架构师就需要抽象思维非常非常好,你要把一个系统的结构全部抽象成接口,你能通过接口去定义一个系统的时候,那时你的架构能力就已经很强了,但是大部分人做不到)
内部类就是在一个类的内部在定义一个类,比如,A类中定义了一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类。
1、成员内部类
package com.xiaodi.operator.oop.demo09;public class Outer { private int id = 10; public void out() { System.out.println("这是外部类的方法"); } public class Inner{ public void in() { System.out.println("这是内部类的方法"); } //内部类访问外部类的私有属性 public void getId() { System.out.println(id); } }}测试:Application
package com.xiaodi.operator.oop;import com.xiaodi.operator.oop.demo09.Outer;public class Application { public static void main(String[] args) { //外部类的实例化大家都懂了吧 Outer outer = new Outer(); //这个内部类要通过外部类来实例化 Outer.Inner inner = outer.new Inner(); //是不是非常奇葩 inner.in(); inner.getId(); }}package com.xiaodi.operator.oop.demo09;public class Outer { private int id = 10; public void out() { System.out.println("这是外部类的方法"); } public static class Inner{ public void in() { System.out.println("这是内部类的方法"); } //外部的id就拿不到了,因为是静态的类存在的时候就存在,那个时候id这个属性还没出生 }}package com.xiaodi.operator.oop.demo09;public class Outer { //局部内部类 写在方法里面的 public void method() { class Inner { public void in() { } } }}package com.xiaodi.operator.oop.demo09;public class Outer { public static void main(String[] args) { //我们正常实例化是像下面这样干的 Apple apple = new Apple(); //匿名内部类就是没有名字去初始化类,不用把实例保存到变量中 new Apple().eat(); //匿名内部类 接口的实现 new UserService() { @Override public void hello() { } }; }}class Apple{ public void eat() { System.out.println("1"); }}interface UserService { void hello();}package com.xiaodi.operator.oop.demo09;public class Outer {}//一个java文件中可以有多个class类,但是只能有一个public class类class A {}大家这里先了解一下就可以,讲内部类主要目的是让大家知道有这个东西,以后分析源码看到,不要不知道这是什么东西就行
本章内容较多,建议看两遍以上,第二遍你会发现一些第一遍不理解的,慢慢理解了
本章内容较多,建议看两遍以上,第二遍你会发现一些第一遍不理解的,慢慢理解了
本章内容较多,建议看两遍以上,第二遍你会发现一些第一遍不理解的,慢慢理解了