基本概念

java类及类的成员:属性,方法,构造器;代码块,内部类 面向对象的三大特征:封装性,继承性,多态性(抽象性)

面向过程(POP)和面向对象(OOP)

面向过程:强调的是功能行为,以函数为最小单位,考虑怎做 面向对象:将功能封装进对象,强调具备了功能的对象。以类/对象为最小单位,考虑谁来做

类(Class)和对象(Object)

是对一切事物的描述,是抽象的,概念上的定义 对象是实际存在的该类事物的每个个体,因而也称为实例 万物皆对象

可变参数

  1. class Person{
  2. //可变个数的形参,0到多个,一个形参匹配多个实参,在类型和形参名之间打三个点
  3. //不能和参数为String[]的形参,重载方法,编译器认为 String ... 和 String[]一样
  4. public void show(String ... strs){
  5. //strs会被当成数组
  6. for(int i=0;i<strs.length;i++){
  7. System.out.println(strs[i]);
  8. }
  9. }
  10. }
  11. Person p1 = new Person();
  12. p1.show("hahahah","shhsdafj","dsfs");

方法参数的传递机制

java只有值传递。

形参是基本数据类型,将实参基本数据类型变量的数据值传递给形参,相当于复制一份数据给形参

形参是引用数据类型,将实参引用数据类型变量的地址值传递给形参

这个地址值,指向原来的数据,在方法里面修改数据,也是只修改原来的数据

封装

程序设计追求 高内聚,低耦合

高内聚:类的内部数据操作细节自己完成,不允许外部干涉 低耦合:仅对外暴露少量的方法用于使用

封装就需要隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可维护性,可扩展性
我们将类的属性私有化(private),同时,提供公共的方式来get和set

  1. class Animal{
  2. //属性设为私有的
  3. private String name;
  4. private int age;
  5. private int legs;
  6. //通过公共的方法去设置和获取值
  7. public int getAge(){
  8. return age;
  9. }
  10. public void setAge(int a){
  11. if(a<0||a>130)
  12. age=0;
  13. else
  14. age=a;
  15. }
  16. }

访问权限修饰符

由小到大排列:

修饰符 内部类 同一个包 不同的子类 同一个工程
private
- [x]

| | | | | (缺省)就是不写 |
- [x]

|
- [x]

| | | | protected |
- [x]

|
- [x]

|
- [x]

| | | public |
- [x]

|
- [x]

|
- [x]

|
- [x]

|

可以用来修饰类的内部结构:属性,方法,构造器,内部类
修饰类只能用 :缺省,public

构造器

如果没有显式的定义类的构造器,则系统默认提供一个空参的构造器

  1. Person p1 = new Person();//这个就是new + 构造器

一旦显式的定义了类的构造器,系统就不提供默认的构造器了,也就是说,要自定义构造器。

  1. class Animal{
  2. //属性设为私有的
  3. private String name;
  4. private int age;
  5. private int legs;
  6. //构造器格式:权限修饰符 类名(参数){}
  7. Animal(){
  8. System.out.println("这是空的构造器");
  9. }
  10. //带参数的构造器
  11. Animal(String a){
  12. name=a;//实例化对象的同时,给属性赋值
  13. }
  14. }

this

this表示当前对象,可调用类的属性,方法和构造器

在方法内部使用,this指向的是这个方法所属对象的引用 在构造器内部使用,表示该构造器正在初始化的对象,就是这个类本身

  1. class Animal{
  2. //属性设为私有的
  3. private String name;
  4. private int age;
  5. private int legs;
  6. //构造器格式:权限修饰符 类名(参数){}
  7. Animal(){
  8. System.out.println("这是空的构造器");
  9. }
  10. //带参数的构造器
  11. Animal(String a){
  12. this();//在构造器里面可以这样调用构造器,因为在构造器里面this表示这个类本身
  13. //this(参数) 必须写在当前构造器的首行,而且一个构造器最多只能用一次this(参数)
  14. name=a;//实例化对象的同时,给属性赋值
  15. }
  16. //如果设置属性的形参和属性变量一样,就要用this指向当前对象
  17. public void setAge(int age){
  18. if(a<0)
  19. this.age=0;
  20. else if(a>130)
  21. this.age=130;
  22. else
  23. this.age=age;
  24. }
  25. public int getAge(){
  26. return age;
  27. }
  28. }

package和import

package

为了更好的实现项目的管理,提出了包的概念。在一个项目中创建多个不同功能的包,写的类就放在不同的包下面

使用package声明,声明类或者接口所属的包,声明在源文件首行

  1. package com.test1;
  2. //声明这个源文件在哪个包下面,要自己创建包,跟创建文件夹一样 com.test1就是包名
  3. //包命名要见名知意
  4. //同一个包下不能命名同名的接口或者类

import

  1. //在源文件中显示的使用import导入指定的包下的类,接口
  2. //写在package声明和class声明之间
  3. import java.util.Scanner;
  4. //用*号表示导入全部,如果是子包下的类,还是要写子包名,*只能导入当前的包的全部类和接口,不包括子包
  5. import java.io.*;
  6. //如果使用的类或者接口是java.lang包下定义的,则可以省略import导入
  7. //如果使用的类或接口是本包下定义的,也可以不用import
  8. //如果要用的类两个包里面都有重名的,只有import一个包,另一个写全限定类名

继承

减少代码冗余,提高复用性。
子类继承父类,子类就拥有了父类的全部属性和方法,便于功能扩展
继承是多态的前提

  1. //父类,超类,基类,superclass
  2. //如果没有显示的声明一个类的父类,则此类继承与java.lang.Object类,Object是所有类的大爹
  3. class Animal{
  4. //属性设为私有的
  5. protected String name;
  6. protected int age;
  7. //父类属性方法等设置为private,子类还是能继承,只是由于权限不能直接调用
  8. protected void eat(){
  9. System.out.println("动物本能的吃了东西");
  10. };
  11. protected void sleep(){
  12. System.out.println("动物本能睡觉");
  13. };
  14. }
  1. //子类,派生类,subclass
  2. public class Dog extends Animal{
  3. //子类继承了父类,还可以单独有属于子类的字段与方法,子类进行拓展
  4. //子类同时还有父类的属性和方法
  5. String color;
  6. public void running(){
  7. System.out.println("狗跑起来了");
  8. }
  9. }
  1. public class test1 {
  2. public static void main(String[] args) {
  3. //Animal a1 = new Animal();
  4. Dog d1 =new Dog();
  5. d1.age=2;
  6. d1.runing();
  7. d1.eat();
  8. System.out.println(d1.age);
  9. }
  10. }

重写

注意:重写(override)和重载(overload)不一样

重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作 重载:同名,不同参的方法复写,参数可以个数不同,按顺序类型不同。调用时根据传入的参数决定调用哪个方法

  1. //子类,派生类,subclass
  2. public class Dog extends Animal{
  3. String color;
  4. public void running(){
  5. System.out.println("狗跑起来了");
  6. }
  7. //重写父类的方法,同名,同参数,就相当于覆盖了父类的方法,不需要加特殊修饰符
  8. //重写不能降低权限修饰符,最差也要相同
  9. //父类返回类型是void,子类重写也只能是void。父类返回类型是A类型,重写后返回类型可以是A类的子类
  10. //父类返回类型是基本数据类型,子类重写的返回类型只能是相同的数据类型
  11. //子类重写的方法抛出的异常类型,不大于父类抛出的异常
  12. public void eat(){
  13. System.out.println("狗吃了东西");
  14. }
  15. }

super

显示的调用父类的属性方法,一般情况都省略。
通常情况,子类重写了父类的方法,可以用super使用父类被重写的方法,super可以用来调用属性,方法,构造器

  1. //子类,派生类,subclass
  2. public class Dog extends Animal{
  3. String color;
  4. String name;//子类和父类声明一样的属性,属性不会被覆盖
  5. public Dog(){
  6. }
  7. public Dog(String name){
  8. //this()和super()在构造器中只能二选一,没有显式声明,默认调用super()
  9. super();//调用父类的没有参数的构造器
  10. this.name=name;
  11. }
  12. public void running(){
  13. System.out.println("狗跑起来了");
  14. }
  15. //重写父类的方法,同名,同参数,就相当于覆盖了父类的方法,不需要加特殊修饰符
  16. public void eat(){
  17. System.out.println("狗吃了东西");
  18. }
  19. public void show(){
  20. System.out.println(this.name);//子类的名字
  21. System.out.println(super.name);//父类的名字
  22. super.eat();//父类的方法
  23. }
  24. }

多态

一个事物的多种形态。

  1. //正常情况下,我们需要一个动物对象,会new一个动物类的对象
  2. Animal a1 = new Animal();
  3. //我们需要一个动物,猫也是动物
  4. Animal a2 =new Cat();
  5. //狗也是动物
  6. Animal a3 =new Dog();
  7. //所以动物有多种形态,这就是对象的多态性,猫狗都是动物的子类
  8. //父类的引用指向子类的对象

多态的使用

  1. 类的继承关系
  2. 方法的重写
    1. //多态的使用
    2. a3.eat();//用对象的子父类同名方法的时候,会发现是执行的子类重写的方法。这就是虚拟方法调用
    3. //Dog类中延展了一个running方法,但是Animal类中没有定义,这时候就不能调用running方法
    4. //能调用的只能是左边类里面定义过得属性方法。编译看父类中定义的方法,运行时看子类重写的方法
    5. //对象的多态性只适用于方法,不适用于属性(编译和运行都看左边)

    多态不是编译时行为,是运行时行为,因为编译时根本看不出哪个子类,只有运行了才知道

为什么要用多态

  1. //比如这个方法,参数是Animal类型的,我可以传入Cat类对象,也可以传入Dog类对象,什么鸡鸭鱼牛羊猪都可以
  2. //但是如果没有多态,那这么多动物,如果都要使用这个方法那怎么办,要使用狗类,定义一个方法,参数类型Dog
  3. //要使用猫类,定义一个方法参数是Cat类型,无穷无尽
  4. public static void K(Animal animal){
  5. animal.eat();
  6. }

再举个例子,市面上数据库有很多,mysql,sqlserver,oracle等,这是用java操作这些数据库,步骤都差不多,可以说一样的操作,但是由于是不同的数据库,连接肯定不同。
想到操作都差不多,干脆今定义一个父类,父类定义好所有的操作方法,每个数据库都定义一个继承父类的子类。当你需要用什么数据库的时候,就传入数据库的子类对象赋值给父类对象。
通过一个父类对象就可以操作所有的数据库,而不是想用mysql的时候操作mysqldb类,想用oracle的时候,操作oracledb类,这么多数据库,没有多态,找用什么类都要找半天。

向下转型

image.png
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于声明的变量为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

如何才能调用子类特有的属性和方法

  1. //判断对象a3是否是Dog类的实例,如果是返回true,如果不是返回false
  2. //Dog换成Animal也能true
  3. if(a3 instanceof Dog){
  4. Dog d2= (Dog)a3;
  5. d2.running();
  6. System.out.println("转换成功");
  7. }

代码块

在类中用花括号括起来的代码块,可以用static修饰。
类里面的属性,可以声明时就赋值,但是如果声明时不赋值,不可以在类里面对属性进行之后的赋值操作。
如果有一个声明东西需要重复创建操作,创建步骤还听过,哪怕在静态方法里面,每一次 class.fangfa(),都会创建一次,反复创建只会增加内存,写一个静态变量,在静态的代码块里面创建这个复杂的东西,赋值给这个静态变量,最后在静态方法里面直接用这个静态属性就行了,不用调一次方法创建一次,因为静态的属性,代码块在类创建时就执行二了

  1. class A{
  2. static int a;
  3. //a=5;//这种是错误的
  4. static{
  5. //在代码块里面可以进行一系列的赋值操作,静态代码块会在类创建时就执行一次
  6. int s=2;
  7. a= s*3/(s+15);
  8. }
  9. }

final

英文翻译就是:最终的
final可以用来修饰的结构:类,方法,变量

  1. //这个类是最终的,不能往下延续了,不能有子类了,不让其他类继承他
  2. final class A{
  3. final int cc=10;//修饰变量就把变量变成常量了,不能修改,必须初始化赋值
  4. //如果final修饰的是属性,可以初始化赋值,构造器赋值,代码块赋值
  5. final public void BB(){
  6. //这个方法不能被重写,如果类没有final被子类继承,这个方法有final,子类不能重写
  7. }
  8. }

抽象类abstract

随着继承越来越多,类变得越来越具体。而父类应该是一个抽象的概念,不应该有实体,如下思维导图 面向对象 - 图2```java //动物类是抽象类,不能实例化,但是有构造器,便于子类实例化调用 abstract class Animal{ protected String name; protected int age;

  1. //抽象方法,父类也不能实例化,关于动物的方法,吃也好,睡也好,应该是抽象的,没有方法体
  2. //不同的动物怎么吃,怎么睡是不一样的,父类不能具体表示
  3. //包含抽象方法的类一定是抽象类
  4. //非抽象子类,必须重写父类全部抽象方法才能实例化,没重写完全部抽象方法,表示该子类还是一个抽象类
  5. abstract protected void eat();
  6. abstract protected void sleep();

}

  1. <a name="BJJlg"></a>
  2. # 接口interface
  3. 有时候必须从几个类中派生出一个子类,继承他们所有的属性和方法,但是,java不支持多重继承,有了接口,就可以实现多重继承了。接口当做干爹,有多个干爹。
  4. 看上面抽象的思维图,老师,司机 都有 [赚钱工作] 的特征,但是生物类没有,子类人类也没有,不是所有的人都有赚钱的能力。把这种赚钱工作的特征,抽成接口,老师,司机同时实现这个接口,他们都有赚钱工作的特征,学生不实现,没有这个特征。
  5. 接口是一种规范,类需要 赚钱工作这种行为特征,就都需要实现 [赚钱工作] 这个接口,接口里面定义了一些规范,最低多少钱,每小时多少,提成比例,怎么赚等等,实现这个接口的类,都要遵循这些规范
  6. 接口和类一样,有多态性
  7. ```java
  8. //接口和类是并列结构
  9. //接口
  10. interface Money{
  11. //接口中不能定义构造器,不能实例化
  12. //接口通过都是通过类来实现,和继承差不多的意思,但是他叫实现,实现接口的功能
  13. //接口可以定义全局常量,书写时public static final可以不写
  14. public static final int MIN = 1500;//最低工资
  15. //抽象方法, public abstract可以不写
  16. public abstract void do_work();
  17. //静态方法,public可以省略,实现类不能直接使用这个静态方法,跟父类不一样
  18. //只能通过接口调用 接口.methods() 或者自用
  19. public static void methods(){
  20. System.out.println("实现接口后不用重写这个方法");
  21. }
  22. //默认方法,可以通过实现类调用 实现类对象.methods2()
  23. default void methods2(){
  24. System.out.println("这个可以重写");
  25. }
  26. }
  27. interface Teach{
  28. String subject ="语文";
  29. void do_teach();
  30. }
  1. abstract public class Person {
  2. abstract public void eat();
  3. abstract public void sleep();
  4. }
  1. //implements 用来实现接口,既然实现了接口,就必须重写完接口的全部抽象方法,
  2. // 如果没有重写全部接口的抽象方法,那么这个类只能是抽象类
  3. public class Teacher extends Person implements Money,Teach{
  4. public void eat(){
  5. System.out.println("老师在餐厅吃东西");
  6. }
  7. public void sleep(){
  8. System.out.println("老师在家睡觉");
  9. }
  10. //实现接口的方法
  11. public void do_work(){
  12. System.out.println("老师赚钱了,赚了:"+Money.MIN);
  13. }
  14. public void do_teach(){
  15. System.out.println("老师教书,教的是:"+Teach.subject);
  16. }
  17. }
  1. //接口可以继承接口,多继承,多实现
  2. interface AA extends Money,Teach{
  3. }

接口多态例子(代理模式)

多学习思考这种思想

  1. public class test1 {
  2. public static void main(String[] args) {
  3. Server server =new Server();//一个真实的服务器对象,可以当做就是你自己的服务器
  4. //创建一个代理服务器对象,传入真实服务器对象,代理服务器设置好代理后,让真实服务器用设置好的代理上网
  5. new ProxyServer(server);//形参是NetWork接口类型,而实参是Server实现类,这就是接口的多态性
  6. }
  7. }
  8. //网络接口
  9. interface NetWork{
  10. //只要能连上网络接口,就有一个上网的功能
  11. void shang_wang();
  12. }
  13. //服务器类,实现了网络接口,有上网的功能
  14. class Server implements NetWork{
  15. //服务器类里面的方法是用本服务器去真实的访问网络
  16. public void shang_wang(){
  17. System.out.println("真实的服务器访问网络");
  18. }
  19. }
  20. //代理服务器,也实现了网络接口,有上网的功能
  21. class ProxyServer implements NetWork{
  22. private NetWork work; //真正联网的东西,实例化时传入初始化
  23. public ProxyServer(NetWork work){
  24. this.work=work;
  25. }
  26. public void setProxy(){
  27. System.out.println("代理服务器设置代理");
  28. }
  29. //代理服务器里面的方法是用代理访问网络
  30. public void shang_wang(){
  31. setProxy();//访问网络之前,先设置代理
  32. //设置了代理后,就开始联网的操作,但真正的联网不是代理服务器连接的
  33. work.shang_wang();//让真正联网的东西去执行上网的操作
  34. //我只是代理,帮你设置了代理ip等操作,我设置完了你自己联网,
  35. //如果不经过代理服务器,自己联网,没有设置代理这一系列的步骤,能不能连上就是另一回事了,所以才叫代理
  36. }
  37. }