第一章 面向对象和面向过程
面向对象(OOP[Object Oriented Programming])和面向过程(POP[procedure oriented programming])都是一种软件编程设计思想 1. 面向过程强调功能行为 2. 面向对象是将功能封装进对象,强调具备了功能的对象 3. 面向对象强调运用人类在日常的思维逻辑中采用的思想方法与原则解决问题 |
第1节 面向过程
第2节 面向对象
第二章 类和对象
1 2 | Java语言是一门面向对象的语言,那么Java怎么实现的面向对象呢? 类和对象是Java语言实现面向对象的核心 |
第1节 类
类的介绍
1 | 描述现实生活中一类事物的总称 |
类的语法格式
1 2 3 4 5 6 | [修饰符] class 类名{ //类体 } 1. 修饰符包括权限修饰符(public,protected,private,默认)还有其他修饰符(static,final) 2. class关键字,声明类的关键字 3. 类名:自定义,满足标识符命名原则 |
类的描述
1 2 3 4 | 使用类描述现实生活中的对象 类描述人 类描述车 类描述狗 |
按照我们人类的自然思维,你是怎么知道他是一条狗的,凭什么认为它是一条狗,而不是一台汽车. | |
我们人类之所以能够分辨现实生活中的各个对象,比如看见汽车就知道他是汽车,看见狗就知道它是一条狗,是因为每一个对象都有他独有的特点,以及功能.这种现实生活中分辨对象的的特点和功能在Java语言中我们称之为属性(成员变量)和行为(方法或者函数). |
案例一(描述人)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * 描述人 */ public class Person { //名字 String name; //年龄 int age; //性别 String gender; //国籍 String nationality; public void run() { System.out.println("跑..."); } public void jump() { System.out.println("跳..."); } } |
案例二(描述车)
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * 描述车 */ public class Car { //品牌 String brand; //颜色 String color; public void driver() { System.out.println("驾驶..."); } } |
案例三(描述狗)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * 描述狗 */ public class Dog { //名字 String name; //年龄 int age; //颜色 String color; //性别 String gender; public void eat() { System.out.println("狗吃骨头..."); } } |
第2节 对象
对象的介绍
1 | 类的具体实例 |
可以将车的设计图看成类,类的设计决定了对象的功能,所以Java语言设计其实就是类设计 将具体的车看成对象 对象是根据类得到的 |
对象的创建方式
1 | 使用new关键字进行对象创建 |
对象创建的语法
1 2 3 4 5 6 | new 类名() 对象创建的方式new关键字加上类名在加一对小括号 eg: Person p = new Person(); Car c = new Car(); Dog d = new Dog(); |
第3节 类成员之三构造器
构造器语法
1 2 3 | [修饰符] 类名(参数列表){ //初始化语句 } |
构造器的作用
1 | 创建对象,给对象进行初始化. |
构造器的调用
1 2 | 1. 使用关键字new调用构造方法 2. 在类的内部使用this关键字调用 |
构造器的分类
1 2 3 | 根据参数不同,构造器分为如下两类 1. 隐式无参构造器(系统默认提供) 2. 显示定义一个或多个构造器(无参、有参) |
构造器特点
1 2 3 4 5 | 1. Java语言中,每个类都至少有一个构造器 2. 默认构造器的修饰符与所属类的修饰符一致 3. 一旦显式定义了构造器,则系统不再提供默认构造器 4. 一个类可以创建多个重载构造器 5. 父类的构造器不可被子类继承(后面在继承的时候演示) |
第4节 this关键字
this介绍
1 | this代表当前类的对象,可以使用this调用类中的成员,比如属性、方法、构造方法等. |
this举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | //1. this调用当前类中的属性 public class User { String userName; int age; public User(String userName, int age) { //this用在构造方法中给成员变量进行初始化 this.userName = userName; this.age = age; } } //2. this调用当前类中的方法 public class User { String userName; int age; public String getUserInfo(){ return userName+"-->"+age; } public String print(){ //使用this调用当前类中的方法 return this.getUserInfo(); } } //3. this调用当前类中的构造方法(构造方法也是方法,所以this也可以调用) public class User { String userName; int age; public User(String userName) { this.userName = userName; } public User(String userName, int age) { //this调用一个参数的构造方法 this(userName); this.age = age; } } |
第5节 package和import
package介绍
1 2 3 4 | 1. 在Java语言中为了更好的实现项目中的类的管理,Java语言提出了包的概念. 2. 使用package声明类所属的包,声明必须在.java源文件的首行. 3. 包属于标识符,在命名的时候要符合标识符的命名规范. 4. 每点(.)一次在计算机上就代表着一层文件夹目录 |
JDK中自带包介绍
1 2 3 4 | 1. java.lang 2. java.io 3. java.util ... |
自定义包
1 2 3 4 5 6 | package cn.ukoko; //当前Hello类属于cn.ukoko包下 public class Hello{ publlic static void main(String[] args){ System.out.println("Hello..."); } } |
import介绍
如果在一个包下的类中使用了另一个包中的类,那么需要使用import关键字进行导入(除了java.lang包) |
第三章 类的高级特性一
第1节 static和final
static修饰符
1 2 3 4 5 6 7 8 9 10 11 | static可以修饰类、属性、方法、代码块,不能修饰构造方法,修饰类只能修饰内部类 在日常开发中最常见的是使用static修饰属性和方法,像修饰代码块以及内部类很少见. 被static修饰的属性和方法的特点: 1. 被static修饰的属性叫做类属性,直接类名.属性名方式调用,不需要创建对象之后使用对象名.属性调用. 2. 被static修饰的方法叫做类方法,直接类名.方法名方式调用,不需要创建对象之后使用对象名.方法名调用. 3. static修饰的方法中不能使用this,因为static是随着类加载而被加载,this是对着对象创建而创建,类要比对象优先存在. 4. 静态可以访问静态,静态不能访问非静态. 5. 非静态可以访问静态. 6. 静态变量由于属于类而不是属于对象,所以static修饰的变量在内存中只存在一份,被当前类的所有对象共享. |
static案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class B { //修饰属性 static int i=0; //代码块 static { } //修饰方法 public static void sum() { } //内部类 public static class C{ } } |
final修饰符
1 2 3 4 5 | final可以修饰类、属性、方法以及方法入参,不能修饰构造方法 1. final修饰的类不能被继承 2. final修饰的属性不能被2次赋值(常量) 3. final修饰的方法不能被重写 |
final案例
1 2 3 4 5 6 7 8 9 10 | //修饰类 public final class B { //修饰属性 final int i=0; //修饰方法 public final void sum(final int a) { //修饰方法入参 //修饰局部变量 final int m=0; } } |
第2节 类成员之四代码块
代码块
1 2 3 | { //代码块 } |
静态代码块
1 2 3 | static{ //静态代码块 } |
静态代码块,代码块,构造方法的执行顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class User { //构造方法 public User() { System.out.println("我是构造方法"); } //代码块 { System.out.println("我是代码块..."); } //静态代码块 static { System.out.println("我是静态代码块"); } public static void main(String[] args) { new User(); new User(); new User(); /** * 创建3个对象 * 1. 静态代码块只执行了一次,代码块和构造方法每次创建对象都会被执行 * 2. 静态代码块最先被执行 * 3. 代码块比构造方法先执行 */ } } |
第3节 面向对象三大特性
1 | 面向对象三大特性: 封装、继承、多态 |
3.1 封装
封装介绍
1 2 3 | 封装字面意思就是包装,专业点叫做隐藏,在Java语言中就是对属性和行为的隐藏. Java语言提供了四种权限修饰符(private,缺省,protected,public)可以修饰Java的属性和行为,其中private修饰符帮助我们完成封装 |
没有封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class TestDemo01 { public static void main(String[] args) { Person p = new Person(); p.name="李雷"; /* * 赋值没问题,整数类型 * 但是不符合现实,现实中人不可能活200岁 * 可不可以想一种办法,将这个age属性隐藏起来让p.name找不到,这样就不会被随便赋值了 */ p.age=200; } } class Person { public String name; public int age; } |
使用封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public class TestDemo01 { public static void main(String[] args) { Person p = new Person(); p.name="李雷"; /* * 属性私有化,age变量的作用范围只能在当前类中有效 * 所以在TestDemo01类中访问不到age * 但是我还想给age赋值应该怎么办呢? */ //p.age=200; } } class Person { public String name; //私有化属性 private int age; /* * 私有化属性之后提供set方法给私有化属性赋值 * 使用方法赋值可以灵活的校验所传递的参数是否合法 * 然后判断是否给属性赋值 */ public void setAge(int age) { if(age<0 && age<=120) { this.age = age; }else { System.out.println("输入的年龄不合法...."); } } } |
封装的优势
1 2 | 1. 重用: 封装好一个功能类,对外提供使用细节,不必关心内部实现 2. 安全: 私有化属性,有些不能给用户看的就不需要给用户看,只把能给用户看的显示出来 |
4个权限修饰详解
1 2 | Java语言提供了四个权限修饰符分别为 private,缺省,protected,public 四个修饰符的权限范围为: |
修饰符 | 类内部 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
private | Yes | No | No | No |
default | Yes | Yes | No | No |
protected | Yes | Yes | Yes | No |
public | Yes | Yes | Yes | Yes |
3.2 继承
继承的介绍
1 | 继承和现实生活中的"继承"的相似之处是保留一些父辈的特性,从而减少代码冗余,提高代码的可重用性. |
继承的语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Person { public String name; public int age; } /* * 使用关键字extends实现两个类之间的继承关系 * Person表示父类或者基类或者超类 * Student表示子类或者派生类 */ class Student extends Person{ public String school; } |
一个父类可以派生出多个子类,但是一个子类只能有一个父类 Java语言不支持多继承,但是支持多层继承 |
继承的特点
1 2 3 | 1. 子类继承了父类,就继承了父类的方法和属性 2. 在子类中,可以使用父类中定义的方法和属性,也可以创建新的属性和方法 3. 子类不能直接访问父类中私有的(private)的成员变量和方法 |
方法重写
1 2 3 4 5 6 | 在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重写或者叫覆盖.在程序执行时,子类的方法将覆盖父类的方法. 1. 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型 2. 重写方法不能使用比被重写方法更严格的访问权限 3. 重写和被重写的方法须同时为static的,或同时为非static的 4. 子类方法抛出的异常不能大于父类被重写方法的异常 |
super
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 在Java类中使用super来调用父类中的指定操作 1. super可用于访问父类中定义的属性 2. super可用于调用父类中定义的成员方法 3. super可用于在子类构造方法中调用父类的构造器 注意: 1. 当子父类出现同名成员时,可以用super进行区分 2. super的追溯不仅限于直接父类,祖宗类也可以 3. super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识 //案例 public class A { public static void main(String[] args) { B b = new B("李雷","北京大学"); String info = b.getInfo(); System.out.println(info); } } class B extends C{ private String name; public B(String name,String school) { super(school); this.name = name; } @Override public String getInfo() { return name+"的学校为:"+super.getInfo(); } } class C{ private String school; public C(String school) { this.school = school; } public String getInfo(){ return school; } } |
子类的实例化过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** * c... * b... * 上面是实例化子类的结果 * 1. 在实例化子类的时候父类先被实例化 * 2. 默认都不添加构造方法的情况下子类的无参构造方法调用父类的无参构造方法super(); * 3. 如果父类添加有参构造方法并且覆盖了原有的默认无参构造方法,那么子类也必须有对应的构造方法,调用现有的有参构造方法 */ public class A { public static void main(String[] args) { B b = new B();//实例化子类 } } class B extends C{ public B() { System.out.println("b..."); } } class C{ public C() { System.out.println("c..."); } } |
3.3 多态
多态的产生
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Java语言编写的代码,从编写到运行要经历的步骤: Xxx.java -javac- Xxx.class -java- 运行 编译时期类型检测: 编译时类型由声明该变量时使用的类型决定. 运行时期类型检测: 运行时类型由实际赋给该变量的对象决定. 上面两句话总结成一句话就是: 编译看左侧,运行看右侧. 下面我们举一个例子: //没有多态 ① String s="Hello"; ② boolean f=s.equals("Hello"); 编译的时候看左侧①中声明一个String类型的变量,起名为s;②中的s是String类型,这个类中有equals方法,所以编译通过 运行的时候看右侧①中在内存中开辟一个空间存储"Hello"值;②中的s对象是"Hello"和另一个"Hello比较",所以运行通过 //使用多态 Animal a=new Bird(); //如果成立,那么这就属于多态 根据咱们前面学习的知识右侧对象的类型一定要和左侧的类型相同,这时候编译才能通过,但是如果等号左右两侧类型不相同,编译器也可以通过,这就出现了多态;当前多态是有前提条件的. |
多态产生的原因
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * 1. 等号左右两侧的数据类型满足继承的关系. * 2. 等号左侧的数据类型是右侧对象数据类型的超类类型. */ public class A{ public static void main(String[] args) { B b=new C();//父类引用指向子类对象(多态使用) } } class C extends B{ } class B{ } |
基本类型变量和引用数据类型变量区别
1 2 3 4 | 基本数据类型: int a=100;一个变量值只能有一个确定的数据类型,所以不能使用多态 引用数据类型: Animal a1=new Bird();Animal a2=new Dog(); Java虽然不能多继承,但是能多层继承,所以一个父类可以派生出多个子类 |
多态的局限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * 如果父类在派生出来的子类中新添加了属性或者方法,那么在使用多态时,该变量就不能再访问子类中添加的属性和方法. * 如果一定要调用子类中新增的属性或者方法,那么可以使用向上转型的方式进行造型.因为父类引用指向的是子类对象,也 * 就是说父类的变量值就是子类的对象,这是可以对这个变量进行向上转型,转成子类.B b=new C(); C c2=(C)b;造型 */ public class A{ public static void main(String[] args) { B b=new C();//父类引用指向子类对象(多态使用) int x = b.b;//编译通过 int y = b.c;//编译不通过,编译看左侧,左侧b对应所在的类中没有c这个属性 } } class C extends B{ public int c=20; } class B{ public int b=10; } |
第四章 类的高级特性二
第1节 抽象类
抽象类介绍
1 2 | 抽象类又称为模板类,在类的继承中,随着新子类的建立,子类会越来越具体,相比于子类,父类会变的越来越通用. 有时候为了让父类更通用,父类会设计的特别抽象,以至于没有具体实例(就算创建了对象,这个对象也不能具体表示现实生活中的哪个对象).这样的类我们叫它抽象类.
|
abstract关键字
1 2 3 4 5 6 7 | 1. 用abstract关键字来修饰一个类时,这个类叫做抽象类 2. 用abstract来修饰一个方法时,该方法叫做抽象方法,抽象方法只有方法声明,没有方法体. eg: abstract int abstractMethod(int a); 3. 含有抽象方法的类必须被声明为抽象类 4. 抽象类不能被实例化.抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体.若没有重写全部的抽象方法,仍为抽象类. 5. 不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法 6. 抽象类的成员和普通类设计相同 |
抽象类的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public abstract class Animal { public abstract void eat(); } class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); } } class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼..."); } } |
第2节 接口
接口介绍
1 2 3 4 | 1. 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法.但是,Java不支持多重继承.有了接口,就可以得到多重继承的效果 2. 接口(interface)是抽象方法和常量值的定义的集合 3. 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现 4. 一个类可以实现多个接口,接口也可以继承其它接口 |
接口特点
1 2 3 4 5 | 1. 用interface来定义 2. 接口中的所有成员变量都默认是由public static final修饰的 3. 接口中的所有方法都默认是由public abstract修饰的 4. 接口没有构造器 5. 接口采用多继承机制 |
接口语法
1 2 3 4 5 6 7 8 9 10 | public interface Animal { int leg=10; void eat(); } class Dog implements Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); } } |
接口注意事项
1 2 3 | 1. 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化.否则,仍为抽象类 2. 接口的主要用途就是被实现类实现.(面向接口编程) 3. 与继承关系类似,接口与实现类之间存在多态性 |
工厂模式/代理模式
第3节 内部类
内部类的概念
1 | 内部类顾名思义就是声明在类的内部的类叫做内部类 |
内部类的分类
1 2 3 4 | 1. 成员内部类 2. 静态内部类 3. 局部(方法)内部类 使用极少,不做讲解 4. 匿名内部类 |
为什么使用内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * Java不支持多继承 * 如果A类想同时继承C类和D类中的方法是不可能的 * 但是可以使用内部类的方式,间接解决不能多继承问题 * A类先继承C类,将C类中的sum方法继承到A类中 * 在A类中创建内部类B,让这个内部类B继承D类,这样D类中的方法就被继承到了B中 * B类又是A类的成员,这样间接的D类中的方法和C类中的方法都在A类中了. * 内部类拥有类的基本特性,不止可以继承还可以实现接口... */ public class A extends C{ public class B extends D{ } } class C{ public void sum() { } } class D{ public void count() { } } |
内部类的介绍
- 成员内部类
1 2 3 4 5 6 7 | 1. 作为类的成员存在,可以被任意权限修饰符修饰 2. 可以调用外部类的所有信息 3. 可以和外部类属性和方法重名,调用时外部类名.this.属性/方法即可 4. 外部类调用内部类信息 需要new 内部类对象使用 5. 其他类调用内部类信息需要创建内部类对象,创建方式: 5.1 先创建外部类对象 A a = new A(); 5.2 通过外部类对象创建内部类对象 A.B b = a.new B(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | //外部类 public class A { private int aId=100; private int common=1000; private static String aName="AAA"; //外部实例方法 public void aInstanceMethod() { System.out.println("外部实例方法..."); } //外部静态方法 public static void aStaticMethod() { System.out.println("外部静态方法..."); } //成员内部类 public class B{ private int common=1000; //定义内部类方法 public void show() { //如果内部类属性和外部类属性同名,输出的是内部类属性 System.out.println("内部common="+common); //访问外部类属性(与内部类同名) System.out.println("外部同名属性common="+A.this.common); //访问外部类非静态属性(与内部类非同名) System.out.println("外部类非静态属性(与外部类非同名)aId="+aId); //访问外部类静态属性(与内部类非同名) System.out.println("外部类静态属性(与外部类非同名)aName="+aName); //访问外部类方法(非静态) aInstanceMethod(); //访问外部类方法(静态) aStaticMethod(); } } //外部类方法访问内部类方法 public void aMethos() { //创建内部类对象 B b = new B(); //调用内部类方法 b.show(); } } //其他类调用内部类对象 public static void main(String[] args) { //外部类对象 A a = new A(); //通过外部类创建内部类对象 A.B b = a.new B(); b.show(); } |
- 静态内部类
1 2 3 4 5 6 | 1. 作为类的静态成员存在,可以被任意权限修饰符修饰 2. 只可以调用外部类static相关联的信息 3. 外部类使用时 类名.信息即可 4. 其他类调用内部类信息时: 4.1 调用静态内部类静态方法 外部类名.内部类名.内部类静态方法 4.2 调用静态内部类实例方法 外部类名.内部类名 变量名 = new 外部类名.内部类名(); 变量名.内部类方法名 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | //外部类 public class A { private static String aName="AAA"; //外部类实例方法 public void aInstanceMethod() { System.out.println("外部类实例方法..."); //调用外部类的静态方法 B.bStaticMethod(); } //外部类静态方法 public static void aStaticMethod() { System.out.println("外部类静态方法..."); //调用外部类的静态方法 B.bStaticMethod(); } //静态内部类 public static class B{ //内部类实例方法 public void show() { //调用外部类静态属性 System.out.println("外部类静态属性aName="+aName); //调用外部类静态方法 aStaticMethod(); } //内部类静态方法 public static void bStaticMethod() { System.out.println("内部类静态方法..."); } } } //其他类 public static void main(String[] args) { //访问静态内部类的静态方法 A.B.bStaticMethod(); //访问静态内部类的实例方法 A.B b = new A.B(); b.show(); } |
- 局部(方法)内部类
1 2 3 4 | 1. 声明在方法内部,只能在方法中使用,具备类的基本特性,类前不能有访问权限修饰符 2. 不能在类中声明静态信息,因为方法结束后内存需要释放 3. 可以直接访问方法的局部变量,但是无法修改 4. 可以随意访问外部的所有信息 |
1 2 3 4 5 6 7 8 9 10 | //外部类 public class A { public void m1() { //局部内部类 class B{ } } } |
- 匿名内部类
1 | 匿名内部类,顾名思义就是没有名字的内部类,咱们上面的内部类不管在类中的什么位置都有名字,匿名内部类却没有名字. |
语法
1 | A a = new A(){@Override}; //A是一个接口或者抽象类 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public interface A { void add(int x,int y); } public class TestDemo { public static void main(String[] args) { new A() { @Override public void add(int x, int y) { System.out.println(x+y); } }; } } |