栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java近夏山潮

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java近夏山潮

面向对象 面向过程&面向对象

面向过程:

  • 线性思维 第一步做什么,第二步做什么…
  • 处理简单问题

面向对象:

  • 分类思维 物以类聚 解决问题的时候首先进行分类,然后对分类进行单独思考。
  • 适合处理复杂问题,可用于多人协作

​ 对于描述复杂的事物,从宏观上把握、从整体上分析,需要使用面向对象的思路来分析整个系统;而具体到微观操作,用面向过程的思路处理。

什么是面向对象

面向对象编程(Object-Oriented Programming,OOP)

本质:以类的方式组织代码,以对象的形式封装数据

抽象

三大特性:

  • 封装 把数据包起来
  • 继承
  • 多态

对象+…+对象→类 对象是具体的事物;类是对对象的抽象

从代码运行角度,先有类再有对象

回顾方法及加深 方法的定义
  • 静态的属性
  • 动态的行为
package oop;
public class OopDemo01 {        //class 表示一个类
    //main 方法
    public static void main(String[] args){
    }

    
    public String asyHello(){
        return "hello,world";
    }

    public void hello(){
        return;
    }

    public int max(int a,int b){
        return a>b?a:b;
    }
}

break:跳出switch,结束循环 return:结束本方法,返回一个结果

方法名:驼峰原则+见名知意

参数列表:(参数类型,参数名) …

异常抛出:

public void readFile(String file) throws IOException{
    
    }
方法的调用
  • 当方法是静态方法时,在另一个类中也可以通过 类名.方法名 进行调用

  • 当方法是非静态时,需要将类实例化

package oop;
public class OopDemo02 {

    public static void main(String[] args){
        //实例化这个类 new
        Student student = new Student();
        student.say();

    }

    public static void a(){		//一个静态一个非静态的类不能相互调用
        b();
    }
    public void b(){}
}

结果:
java: 无法从静态上下文中引用非静态 方法 b()
package oop;
public class OopDemo03 {
    public static void main(String[] args){
        int add = new OopDemo03().add(1,2);  //当方法是静态的时候,直接引用即可     形式参数和实际参数的类型要对应
        System.out.println(add);
    }

    public int add(int a,int b){    //形参
        return a+b;
    }
}

结果:
3

值传递:

package oop;
//值传递
public class OopDemo04 {
    public static void main(String[] args){
        int a = 1;
        System.out.println(a);

        change(a);
        System.out.println(a);
    }

    public static void change(int a){   //没有返回值,a=10只存在这个方法中
        a = 10;
    }
}

引用传递:

package oop;
//引用传递:对象,本质还是值传递
public class OopDemo05 {
    public static void main(String[] args){
        Person person = new Person();
        System.out.println(person.name);
        change(person);
        System.out.println(person.name);
    }
    public static void change(Person person){
        person.name = "小龙";	//这里的Person是一个对象,指向Person这个类,修改的是Person类中的name
    }
}

//一个类中只能有1个public class,但是可以有多个class
//定义了一个Person类,有一个属性:name
class Person{
    String name;
}

结果:
null
小龙
类和对象的关系
  • 类是一种抽象的数据类型/模板,对某一类事物的概括,但是不能代表这一类事务
  • 对象是抽象概念的具体实例
创建和初始化对象

使用new关键字创建对象:

  • 分配内存空间
  • 给创建好的对象进行默认的初始化
  • 对类中构造器的调用

结果:
null
0

结果:
小明
13
null
0

就体现了:以类的方式组织代码,以对象的形式封装数据

构造器

也叫“构造方法”,是创建对象时必须要用的:

  • 必须和类的名字相同
  • 必须没有返回值类型,也不能写void

查看class文件

在Project Structure里点击Modules,添加一个根目录

就会生成这样的class文件

然后就可以看到,虽然源文件什么方法都没写,但是class文件会自动帮忙写一个方法(没有返回值),并且方法名==类名。

设置断点+Debug之后,就可理解构造器的作用:

构造器的作用
  • 使用new关键字,本质是调用构造器
  • 用来初始化值
  • 一旦定义了有参构造,无参就必须显示定义(无参构造就必须为空,如图)

但是如果加入了参数,就会调用有参构造,如下图所示:

快捷键

Alt+Ins → Constructure → OK:默认生成有参构造

Alt+Ins → Constructure → select no:生成无参构造

创建对象的内存分析

在Application中new了两个对象:dog和cat,同时还给dog的属性进行赋值,内存中的大概过程如下:

  • 首先把Application这个类中的代码放入堆中的方法区,包括main()方法、常量池(3不是常量,是int类型的数字)

  • 然后开始在栈中执行main()方法,执行了

    Pet dog = new Pet();
    

    这个操作,如图

    new pet() 就需要将pet类加载到方法区,包括他自己的一些属性(name;age;shout)

    通过这个模板生成了一个具体对象 dog (注意在栈中引用,实际上在堆中),在堆中实际分配了内存地址,同时也具有了刚刚引用到方法区中Pet的属性(属性也叫字段Field、成员变量)

  • 然后执行对name、age的赋值

  • 又new了一个pet:cat,和dog类似,但是没有对属性进行赋值

    引用变量真正是指向堆中的具体对象,只是在栈中保存了一个变量名字。

    注意:引入Application这些类的时候同时生成了"静态方法区",以便其他对象能够直接引用。

封装

设计程序应该追求”高内聚,低耦合“

  • 高内聚:类的内部数据操作细节自己完成,不让外部干涉

  • 低耦合:仅暴露少量方法给外部使用

    封装(数据的隐藏):禁止直接访问一个对象中数据的实际表示,应该通过操作接口进行访问

    如下图所示,当属性是private时,没有name选项,当改成public时,就有了name。

    举例:

快捷键

Alt+Ins→Getter and Setter,点击OK就会自动帮忙生成get和set!

还可以在封装里添加检验条件,对输入进行检查

封装的作用:

  • 提高程序安全性,保护数据
  • 隐藏代码的实现细节(调用者看不到类干了什么)
  • 统一接口(所有的接口都是get、set)
  • 提高系统的可维护性
方法重载

例如println()可以输出各种数据,就是因为里面写了很多方法的重载如上所示,查看源码之后发现里面的类很多,但是都叫println()。例如在括号里多加一个参数,就会变成另外一个类

继承
  • 对某一批类的抽象(是类和类之间的一种关系),以实现对现实世界更好的建模。
  • 继承关系的两个类,一个是子类(派生类),一个是父类(基类)。子类继承父类用extends表示(is a)。
  • 只有单继承(一个爸爸能有多个儿子,但是一个儿子只能有一个爸爸)。

继承:

组合:

public class Student{
	Person person;
}
子类继承了父类,就会拥有父类全部的方法


如上图,子类Student继承了父类Person,所以Application中也有这2个方法

如果换成private或final(属性一般都是私有的),私有的是无法继承的

但是如果想要改变私有的变量,可以借助get、set。

继承树

快捷键:ctrl+H

对Object类的解释:

删空Person类之后,在Application中仍然有很多方法。因为在Java中,所有的类都默认直接或间接阶乘Object类。如下图所示:

例1:

例2:

例3:

直接定义继承Object类,继承树仍然没有区别。省略

super

super可以调用父类,如下图所示:

例1:(属性)

例2:(方法)

当然private属性和方法,super也无法调用

如下图所示,使用Alt+Ins在父类和子类分别创建一个无参构造器

如上图所示,Application调用子类Student,但是Student有隐藏代码,于是就先执行了父类,然后执行了子类。super(); 必须放在子类构造器的第一行,否则就会报错,如下图所示:

并且调用构造器的时候,因为super()和this都要放在第一行,所以要么调用父类要么调用子类。

写有参构造的时候,先写一个无参构造。假如在父类Person把无参变成有参,那么子类不仅会报错,还无法写无参构造。

但是如果写成super(“name”);(调用有参),是可以的

注意点
  • super调用父类的构造方法,必须在构造方法的第一行
  • super只能出现在子类的方法或者构造方法中
  • super和this不能同时用

super VS this:

  • 代表的对象不同
    • this:调用者本身这个对象
    • super:代表父类对象
  • 前提不同
    • this:没有继承也可以使用
    • super:只能在继承条件下才能使用
  • 构造方法不同
    • this:调用本类的构造
    • 调用父类的构造
方法重写(重要)

​ 如上图所示,调用父类的方法,但是却指向了子类,是可行的。(理解成爸爸跟儿子要苹果吃)

​ 去掉父类和子类方法中的static,然后删除子类方法,使用快捷键ALt+Ins,选择Override Methods,就剩成了方法重写/Override。该方法默认调用父类的test,如下图所示:

​ 只更改A类的函数,其余不变,进行运行,发现结果出现差异:

​ 这就是方法的重写。B b = new A(); 虽然new了一个A,指向的是B,实际上指向的是A——子类重写了父类的方法。

​ 另外注意,出现了下图所示的箭头,才是重写

总结

需要有继承关系,子类重写父类的方法

  • 方法名相同,方法体不同
  • 参数列表必须相同(否则就变成重载了)
  • 修饰符的范围可以扩大,但是不能缩小(private→default→protected→public)
  • 抛出异常的范围可以缩小,但是不能扩大(粗略理解为异常不能越来越多)
    • ClassNotFoundException(小)不能变成Exception(大)

为什么要重写:

  • 父类的方法,子类不一定需要,或者不一定满足
多态

如图所示,子类继承父类的所有方法

用父类调用子类的方法时,如果父类没有该方法,就无法执行;如果子类和父类都有该方法,并且子类没有重写,那么就调用父类的;如果子类重写了父类方法,就调用子类的。 子类能调用的方法包括子类自己的方法和继承过来的父类的方法。

当然,也可以通过高类→低类,使他能成功运行:

((Student) s2).eat();
总结:
  • 同一方法可以根据发送对象的不同而采用多种不同的行为方式(子类重写了父类的run();方法,但是最后s1、s2的调用都调用到子类方法。)
  • 一个对象的实际类型是确定的,但是指向对象的引用类型有很多(父类等有关系的类)
注意事项
  • 多态是方法的多态,属性没有多态
  • 有父子继承关系 (要不会出现类型转换异常/ClassCastException!:Student→String)
  • 存在的额条件:
    • 继承关系
    • 方法需要重写 (把子类方法里面的super.go(); 改写成System.out.println(“go”)
    • 父类引用指向子类 (Father father = new Son()
  • 不能重写的方法(不能重写也就更不能实现多态):
    • static,属于类,不属于实例
    • final, 常量,无法改变
    • private
Instanceof和类型转换

如上图所示:由于Object和Person跟Student是父子关系,所以前三个都是true,第四个和第五个是false。

将Object换成Person,除了最后一个由于完全没有联系之外,其余均有联系,结果不变。

换成Student之后,前三行都可能有联系,所以是true。最后两行属于两个分支,编译出现错误。

公式
System.out.println(X is instanceof Y);	
//编译能不能通过就要看X和Y是否存在父子关系(可以是间接父子关系)

student是Person类,该类没有go方法,需要转化成其子类,如下图所示:

总结
  • 父类引用指向子类的对象
  • 把子类转换为父类,向上转型即可,不用强制转换
  • 把父类转换成子类,需要强制转换 (可能丢失一些方法)
  • 方便方法的调用,减少重复的代码
Static关键字详解
  • 静态属性

图中的静态变量age对于Studen这个类而言,在内存中只有一个;能被类中所有的实例共享。

  • 静态方法

不能直接调用非静态的run方法,但是可以通过"对象.方法"的方式来调用:

new Student().run();

而静态方法的调用就比较简单了,如上图所示。

​ 非静态方法run()可以调用静态方法go();静态方法只能调用静态方法。

静态代码块

如上图所示,只在第一次调用才会率先执行静态代码块,然后依次执行匿名代码块和构造方法。

静态导入包

可以通过导入包中的具体函数来减少后面的代码量。

抽象类

继承了抽象类的子类需要进行重写或者同为抽象类,否则出错
抽象类不能new出来,如下图所示:

特点
  • 抽象类不能new出来,只能靠子类去实现他:约束!
  • 抽象类里可以写普通方法,抽象方法必须在抽象类中
  • 抽象的抽象:约束
思考题
  • 抽象类存在构造器吗?
  • 抽象类存在的意义是什么?
    • 提高开发效率
    • 提高可扩展性
接口

普通(只有具体实现) < 抽象类(有具体实现和抽象方法,其中抽象方法由子类去实现) < 接口(只有规范,抽象类的抽象,只能实现约束,将约束和实现分离)

接口/interface就是规范,都要遵守、执行。接口里面写方法会报错

如果要实现接口里面所有的定义,必须要重写接口里面所有的方法

如下图所示,用接口实现多继承:

总结
  • 接口是约束
  • 定义一些方法,让不同的人实现 (多个人用不同的方式实现一种方法)
  • 接口的方法都是public abstract
  • 接口的常量都是public static final
  • 因为接口不是类,就没有构造方法,也就不能被实例化(new)
  • 使用implements可以实现多个接口,但是需要重写里面的方法
内部类

动态内部类:


静态内部类:

加了static之后拿不到id了,因为率先执行静态代码块,然后才定义了id的值。除非把id的定义改成下面这样才能运行:

private static int id = 100;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/832208.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号