返回顶部
扶摇直上九万里,展翅高飞岂可待。

对象

1.类和对象

1.对象的介绍

1.面向过程:自己的事情自己干,代表语言C语言
          洗衣服:每一步自己要亲力亲为 -> 找个盆,放点水,找个搓衣板,搓搓搓
2.面向对象:自己的事情别人帮忙去干,代表语言Java语言    
          洗衣服:自己的事情别人干 -> 全自动洗衣机             
3.为啥要使用面向对象思想编程:懒
  很多功能别人都给我们实现好了,我们只需要直接拿过来使用即可,简化了我们自己的编写过程,减少了我们的代码量   
4.什么时候使用面向对象思想编程:
  调用别人的功能时
  在一个类中想使用别的类中的成员时,就使用面向对象思想编程
  至于我们使用的功能人家怎么实现的,我们不需要关心,我们只需要知道怎么使用即可      
5.怎么使用面向对象思想编程:
  a.new呀,new完点呀-> 点代表的是调用
  b.特殊:如果调用的成员带static关键字,我们不需要new,我们直接类名点即可
public class Demo01Object {
    public static void main(String[] args) {
        /*
           我们想在Demo01Object类中使用Scanner类中的next方法实现录入字符串
           那么我们就需要使用面向对象思想编程
           对象:Scanner-> new出来的
           对象实现好的功能:next()
           我们只需要知道找来Scanner这个对象,就可以调用这个对象中实现好的next方法
           至于next方法怎么实现的,我们不需要关心
         */
        Scanner sc = new Scanner(System.in);
        String data = sc.next();
        System.out.println("data = " + data);
        System.out.println("===================================");
        /*
           我们想在Demo01Object类中使用Random类中的nextInt方法实现随机整数
           那么我们就需要使用面向对象思想编程
           对象:Random -> new出来的
           对象实现好的功能:nextInt()
           我们只需要知道找来Random这个对象,就可以调用Random中的nextInt方法
           至于nextInt怎么实现的,我们不需要关心
         */
        Random rd = new Random();
        int data2 = rd.nextInt();
        System.out.println("data2 = " + data2);
        System.out.println("====================================");
        int[] arr = {1,2,3,4};//[1,2,3,4]
       /* System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            if (i== arr.length-1){
                System.out.print(arr[i]+"]");
            }else{
                System.out.print(arr[i]+",");
            }
        }*/

        /*
           Arrays就是我们找来的对象
           toStrig就是此对象中实现好的功能
           我们只需要调用,怎么实现我们不关心
         */
        System.out.println(Arrays.toString(arr));

    }
}

2.类和对象

2.1类(实体类)_class

1.测试类:带main方法的类,主要是运行代码的
2.实体类:是一类事物的抽象表示形式
        世间万物的分类:比如: 人类   狗类   猫类   鼠标类
组成部分:
  1.属性(成员变量):这一类事物有啥
    a.定义位置:类中方法外  
    b.作用范围:作用于当前类
    c.定义格式: 数据类型 变量名
    d.默认值:
      整数:0
      小数:0.0
      字符:'\u0000'
      布尔:false
      引用:null
          
  2.行为(成员方法):这一类事物都能干啥
    只需要将模块六所学的方法中的static干掉,其他的都一样

成员位置1.png

public class Person {
    //属性-> 成员变量
    String name;
    int age;
    
    //行为 -> 成员方法
    public void eat(){
        System.out.println("人要干饭");
    }
    
    public void drink(){
        System.out.println("人要喝水");
    }
}

描述动物类

public class Animal {
String kind;//品种
String color;//颜色

public void eat(){
  System.out.println("动物要吃饭");
}

public void sleep(){
  System.out.println("动物都睡觉");
}

}

描述手机类

public class Phone {
//属性
String brand;
String color;
int price;

//行为
public void call(String name){
  System.out.println("给"+name+"打电话");
}

public String message(){
  return "给金莲发短信";
}
}

2.2对象

1.概述:一类事物的具体体现
2.使用:
  a.导包: import 包名.类名
    如果两个类在同一个包下,想要使用对方的成员不需要导包
    如果两个类不在同一个包下,想要使用对方的成员需要导包     
    特殊包:java.lang -> 使用lang包下的类不需要导包 -> String        
    友情提示:在学四种权限修饰符之前,尽量让两个类在同一个包下        
  b.创建对象:想要使用哪个类中的成员,就new哪个类的对象
    类名 对象名 = new 类名() -> 比如: Person person = new Person()      
  c.调用成员(成员变量,成员方法) -> 想要使用哪个类中的成员,就用哪个类的对象去点哪个成员
    对象名.成员变量名 = 值
    对象名.方法名() -> 调用的是无参无返回值方法
    对象名.方法名(实参) -> 调用的是有参无返回值方法
    数据类型 变量名 = 对象名.方法名() -> 调用的是无参有返回值方法
    数据类型 变量名 = 对象名.方法名(实参) -> 调用的是有参有返回值方法
public class Person {
    //属性-> 成员变量
    String name;
    int age;
    //行为 -> 成员方法
    public void eat(){
        System.out.println("人要干饭");
    }
    public void drink(){
        System.out.println("人要喝水");
    }
}

public class Demo01Person {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        System.out.println(person.age);
        person.name = "金莲";
        person.age = 26;
        System.out.println(person.name);
        System.out.println(person.age);

        person.eat();
        person.drink();

    }
}

3.练习

需求:用代码去描述一个手机类,在测试类中为手机类中的属性赋值,并且调用手机类中的功能
public class Phone {
    //属性
    String brand;//品牌
    String color;//颜色
    int price;//价格

    //行为
    public void call(String name){
        System.out.println("给"+name+"打电话");
    }
    public String message(){
        return "给金莲发短信";
    }
}

================================================================

public class Demo02Phone {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.brand = "苹果";
        phone.color = "黑色";
        phone.price = 7999;
        System.out.println(phone.brand);
        System.out.println(phone.color);
        System.out.println(phone.price);
        phone.call("金莲");
        String mess = phone.message();
        System.out.println(mess);
    }
}

对象练习1.png

3.匿名对象的使用

1.int i = 10
a.int:是数据类型
b.i:变量名
c.等号右边的10:真正的数据
2.Person p = new Person()
a.等号左边的Person:对象的类型,好比是int   
b.p:对象名
c.等号右边的new Person():真正的数据,是一个Person对象,将这个对象真正创建出来了    
1.所谓的匿名对象:其实就是没有等号左边的部分,只有等号右边的部分(对象)
2.使用:
  new 对象().成员     
3.注意:
  a.如果我们只想单纯的调用一个方法,让方法执行,我们可以考虑使用匿名对象
  b.但是如果涉及到赋值,千万不要用匿名对象    
public class Person {
    String name;
    public void eat(){
        System.out.println("人要吃饭");
    }
}
public class Demo01Person {
    public static void main(String[] args) {
        //原始方式
        Person p = new Person();
        p.name = "金莲";
        System.out.println(p.name);
        p.eat();

        System.out.println("=================");

        //匿名对象
        new Person().eat();

        new Person().name = "大郎";
        System.out.println(new Person().name);//null
    }
}

匿名对象.png

4.内存图

一个对象的内存图

一个对象内存图.png

两个对象的内存图

两个对象内存图.png

phone1和phone2都是new出来的,所以在堆内存中产生了两个不同的空间,所以改变一个空间的数据不会 影响另外一个空间中的数据

两个对象指向同一片空间内存图

两个对象指向同一片内存图.png

phone2是phone1给的,phone1在内存中保存的是地址值,此时phone1和phone2地址值是一样的了,操作的是同一片空间的数据,所以改变一个对象的数据会影响到另外一个对象

5.成员变量和局部变量

1.定义位置不同(重点)
  a.成员变量:类中方法外
  b.局部变量:定义在方法之中或者参数位置      
2.初始化值不同(重点)
  a.成员变量:有默认值的,所以不用先手动赋值,就可以直接使用
  b.局部变量:是没有默认值的,所以需要先手动赋值,再使用     
3.作用范围不同(重点)
  a.成员变量:作用于整个类
  b.局部变量:只作用于自己所在的方法,其他方法使用不了     
4.内存位置不同(了解)
  a.成员变量:在堆中,跟着对象走
  b.局部变量:在栈中,跟着方法走
5.生命周期不同(了解)
  a.成员变量:随着对象的创建而产生,随着对象的消失而消失
  b.局部变量:随着方法的调用而产生,随着方法的调用完毕而消失    
public class Person {
    String name;//成员变量
    public void eat(){
        int i = 10;//局部变量
        System.out.println(i);

        System.out.println(name);//成员变量不用手动赋值可以直接使用,因为有默认值
    }

    public void drink(){
        int j;
        //System.out.println(j);//局部变量没有默认值,所以需要手动赋值再使用
        System.out.println(name);

        //System.out.println(i);//i是eat方法的局部变量,在drink中使用不了
    }
}

6.练习

需求:定义一个类MyDate,属性有 year  month  day

     再定义一个类Citizen(公民类),属性有 name(String类型)  birthday(MyDate类型)  idCard(String),为这三个属性赋值,然后将值取出来
public class MyDate {
    int year;
    int month;
    int day;
}

public class Citizen {
    //姓名
    String name;  //默认值 null
    /*
      生日  MyDate类型

      MyDate属于自定义类型(引用数据类型)
      这种类型要操作之前必须要赋值
      怎么赋值?  需要new对象赋值
     */
    MyDate birthday = new MyDate(); // 默认值 null
    //身份证
    String idCard;  //默认值null
}

public class Test01 {
    public static void main(String[] args) {
        Citizen citizen = new Citizen();
        citizen.name = "涛哥";
        citizen.idCard = "111111111";

        /*
           citizen.birthday获取的是MyDate对象
           再去点year获取的是MyDate对象中的year

           链式调用
         */
        citizen.birthday.year = 2000;
        citizen.birthday.month = 10;
        citizen.birthday.day = 10;

        System.out.println(citizen.name+","+citizen.birthday.year+","+citizen.idCard);

    }
}

给引用数据类型赋值,需要new对象(String比较特殊,可以直接=赋值)

2.封装

1.封装 get/set

1.面向对象三大特征:  [封装]     继承    多态 
2.什么是封装思想:
  a.我们找来了一个对象(洗衣机),只需要按一下按钮就可以了(使用洗衣机功能的过程就是在使用面向对象思想编程的过程),每一个按钮下面都包含了很多内部结构的细节(细节被封装到按钮里面了->封装),在使用的时候有必要了解洗衣机的内部构造吗?我们没有必要去了解内部结构,我们只知道调用就可以了      
    所以,洗衣机来说,将细节隐藏起来了,细节我们不要关注,会对外提供了一个公共的接口(按钮),供我们人类使用        
  b.隐藏对象内部的复杂性,只对外提供公开,公共的接口,便于外界调用,从而提高了系统的可扩展性,可维护性,安全性,通俗来说,把该隐藏的隐藏起来(细节),把该暴露的暴露出来(对外提供的供别人使用的接口),这就是封装思想       
  我们只需要调用这个接口(功能)即可,此接口背后封装起来的细节就开始执行了,但是我们不需要关注细节,只关注公共的接口怎么调用     
  c.将细节隐藏起来,不让外界随便使用,但是我们可以提供一个公共的接口让外界间接使用隐藏起来的细节->封装思想  
1.问题:
  定义成员变量,只要是new出来对象,就可以随便调用,随便赋值,哪怕是不合理的值我们也挡不住,怎么办?
  将属性封装起来(隐藏细节)      
  a.关键字:private(私有化的) -> 被private修饰的成员只能在本类中使用,在别的类中使用不了     
  b.注意:
    将代码放到一个方法中,也是封装的体现
    一个成员被private修饰也是封装的体现,只不过private最具代表性        
  c.private的使用:
    修饰成员变量:private 数据类型 变量名
    修饰方法:将public改成private,其他的都一样        
2.问题:属性被私有化了,外界直接调用不了了,那么此时属性就不能直接赋值取值了,所以需要提供公共的接口
       get/set方法    
      set方法:为属性赋值
      get方法:获取属性值
public class Person {
    private String name;
    private int age;
    //为name提供get/set方法
    public void setName(String xingMing) {
        name = xingMing;
    }
    public String getName() {
        return name;
    }

    //为age提供get/set方法
    public void setAge(int nianLing) {
        if (nianLing < 0 || nianLing > 150) {
            System.out.println("你脑子是不是秀逗啦!岁数不合理");
        } else {
            age = nianLing;
        }
    }
    public int getAge() {
        return age;
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        //person.name = "涛哥";
        //person.age = -18;

        //System.out.println(person.name);
        //System.out.println(person.age);

        person.setName("涛哥");
        person.setAge(18);

        String name = person.getName();
        int age = person.getAge();
        System.out.println(name+"..."+age);
    }
}

private.png

小结:

用private将属性封装起来,外界不能直接调用,保护了属性

对外提供一套公共的接口(set/get方法),让外界通过公共的接口间接使用封装起来的属性

2.this的介绍

1.如果成员变量和局部变量重名时,我们遵循"就近原则",先访问局部变量
2.this概述:代表的是当前对象
3.作用:this可以区分重名的成员变量和局部变量
      this点出来的一定是成员的变量    
4.this代表当前对象,那么具体代表哪个对象呢?
  哪个对象调用的this所在的方法,this就代表哪个对象
public class Person {
    String name;
    /*
       哪个对象调用的this所在的方法,this就代表哪个对象
     */
    public void speak(String name){
        System.out.println(this+"........");
        System.out.println(this.name+"您好,我是"+name);
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person+"=========");
        person.name = "沉香";
        person.speak("刘彦昌");

        System.out.println("==========");

        Person person2 = new Person();
        System.out.println(person2+"+++++");
        person2.name = "奥特曼";
        person2.speak("奥特曼之父");
    }
}

this.png

public class Person {
    private String name;
    private int age;

    //为name提供get/set方法
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //为age提供get/set方法
    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("涛哥");
        person.setAge(16);
        System.out.println(person.getName()+"..."+person.getAge());
    }
}

this1.png

3.构造方法

1.概述:方法名和类名一致并且能初始化对象的方法
2.分类:
  a.无参构造:没有参数
  b.有参构造:有参数,参数是为指定的属性赋值
  c.满参构造:给所有属性赋值      
  以上构造咱们不用记那么详细,我们就记有参和无参构造就可以了      
3.特点:
  a.方法名和类名一致
  b.没有返回值,连void都没有

3.1空参构造

1.格式:
  public 类名(){
      
  }
2.作用:
  new对象使用
      
3.特点:
  每个类中默认都有一个无参构造,不写也有,jvm会自动提供
      
4.使用:一new对象就是在调用构造方法      

3.2有参构造

1.格式:
  public 类名(形参){
      为属性赋值
  }

2.作用:
  a.new对象
  b.为属性赋值
      
3.特点:
  jvm不会自动提供有参构造,但是将有参构造手写出来,jvm将不再提供无参构造,所以建议有参,无参的构造都手写上去
public class Person {
    private String name;
    private int age;

    //无参构造
    public Person(){
        System.out.println("我是无参构造");
    }

    //有参构造
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();

        Person person2 = new Person("涛哥", 18);
        System.out.println(person2.getName()+"..."+person2.getAge());

    }
}

有参构造.png

如何快速知道调用的成员是哪个类中的哪个成员呢?

按住ctrl不放,鼠标点击对应的成员 -> 会跳到对应的位置

4.标准JavaBean

JavaBean 是 Java语言编写类的一种标准规范。符合JavaBean` 的类,要求:

(1)类必须是具体的(非抽象 abstract)和公共的,public class 类名

(2)并且具有无参数的构造方法,有参构造

(3)成员变量私有化,并提供用来操作成员变量的setget 方法。

com.atguigu.controller -> 专门放和页面打交道的类(表现层)
com.atguigu.service -> 专门放业务处理的类 (业务层)
com.atguigu.dao -> 专门放和数据库打交道的类(持久层)
com.atguigu.pojo -> 专门放javabean类
com.atguigu.utils -> 专门放工具类
public class Person {
    private String name;
    private int age;

    //无参构造
    public Person(){
        
    }

    //有参构造
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("金莲");
        person.setAge(26);
        System.out.println(person.getName()+"..."+person.getAge());

        Person person2 = new Person("涛哥", 18);
        System.out.println(person2.getName()+"..."+person2.getAge());

    }
}

编写符合JavaBean 规范的类,以学生类为例,标准代码如下:

public class Student {
    private int sid;
    private String sname;

    public Student() {
    }

    public Student(int sid, String sname) {
        this.sid = sid;
        this.sname = sname;
    }

    public int getSid() {
        return sid;
    }

    public void setSid(int sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }
}

快速生成标准javabean通用快捷键:alt+insert

  1. 生成无参构造:

    idea无参构造.png

2.生成有参构造

idea有参构造.png

3.生成get/set方法:

idea.get.set.png

public class Test01 {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setSid(1);
        s1.setSname("涛哥");
        System.out.println(s1.getSid()+"..."+s1.getSname());

        System.out.println("==============");

        Student s2 = new Student(2, "金莲");
        System.out.println(s2.getSid()+"..."+s2.getSname());
    }
}

小结:

1.知道private的作用嘛?私有的,别的类不能直接调用

2.知道空参构造作用嘛?new对象

3.知道有参构造作用嘛? new对象 为属性赋值

4.知道set方法作用嘛? 为属性赋值

5.知道get方法作用嘛? 获取属性值

6.知道this的作用嘛? 区分重名的成员变量和局部变量

7.知道快捷键生成标准javabean嘛? alt+insert

5.JavaBean怎么来的

1.将来的javabean都是和数据库的表相关联
  a.类名 -> 表名
  b.属性名 -> 列名
  c.对象 -> 表中每一行数据
  d.属性值 -> 表中单元格中的数据

JavaBean.png

javabean添加.png

将页面填写的数据获取到,封装到javabean中,一层一层传递到dao层,然后将javabean中的属性值获取出来放到表中保存 -> 相等于是一个添加功能

javabean遍历.png

将所有的数据查询出来,封装成一个一个的javabean对象,然后将封装好的javabean对象放到一个容器中,将此容器返回 给页面,在页面上遍历展示

模块八重点:
  1.封装:
    a.将细节隐藏起来,不让外界直接调用,再提供公共接口,供外界通过公共接口间接使用隐藏起来的细节
    b.代表性的:
      将一段代码放到一个方法中(隐藏细节),通过方法名(提供的公共接口)去调用
      private关键字 -> 私有的,被private修饰之后别的类不能直接调用,只能在当前类中使用
          
    c.get/set方法
      set方法:为属性赋值
      get方法:获取属性值
          
    d.this关键字:代表当前对象,哪个对象调用this所在的方法this就代表哪个对象
      区分重名的成员变量和局部变量
        
  2.构造:
    a.无参构造:new对象
      特点:jvm会自动为每个类提供一个无参构造
    b.有参构造:new对象  为属性赋值
      特点:如果手写了有参构造,jvm将不再提供无参构造,所以建议都写上
          
  3.标准javabean:
    a.类必须是公共的,具体的
    b.必须有私有属性
    c.必须有构造方法(无参,有参)
    d.必须有get/set方法
        
    快捷键:alt+insert
        
模块九重点:
  1.会定义静态成员以及会调用静态成员
  2.会使用可变参数(会给可变参数传参)
  3.会二分查找(手撕)
  4.会冒泡排序(手撕)
  5.会debug的使用    
  

3.面向对象

1.static关键字

static.png

1.static的介绍以及基本使用

1.概述:static是一个静态关键字
2.使用:
   a.修饰一个成员变量:
     static 数据类型 变量名

   b.修饰一个方法:
      修饰符 static 返回值类型 方法名(形参){
             方法体
             return 结果
      }

3.调用静态成员:
   类名直接调用(不用new对象)

4.静态成员特点:
   a.静态成员属于类成员,不属于对象成员(非静态的成员属于对象成员)
   b.静态成员会随着类的加载而加载
   c.静态成员优先于非静态成员存在在内存中
   d.凡是根据静态成员所在的类创建出来的对象,都可以共享这个静态成员
public class Student {
    String name;
    int age;
    static String classRoom;
}

public class Test01 {
    public static void main(String[] args) {
        //先给静态成员赋个值
        Student.classRoom = "222";

        Student s1 = new Student();
        s1.name = "郭靖";
        s1.age = 28;
        //s1.classRoom = "111";

        System.out.println(s1.name+","+s1.age+","+Student.classRoom);

        System.out.println("==============");

        Student s2 = new Student();
        s2.name = "黄蓉";
        s2.age = 26;
        //s2.classRoom = "111";
        System.out.println(s2.name+","+s2.age+","+Student.classRoom);
    }
}

2.static修饰成员的访问特点

1.在静态方法中能直接访问非静态成员嘛?  不能
  想要调用的话:new对象调用  
    
2.在非静态方法中能直接访问静态成员嘛? 能
  a.同类:
    直接调用
    类名调用
        
  b.不同类:
    类名调用   
3.在静态方法中能直接访问静态成员嘛?能
  a.同类:
    直接调用
    类名调用        
  b.不同类:
    类名调用
    
4.在非静态方法中能直接访问非静态成员嘛?能
  a.同类:
    直接调用    new对象调用
        
  b.不同类:
    new对象调用

总结:

1.不管在不在同一个类中,非静态成员都可以new对象调用

2.不管在不在同一个类中,静态成员都可以类名调用

问题1:既然static成员那么好使(类名直接调用),那么我们在实际开发中,能不能将所有的成员都定义成静态的呢?
不能

原因:由于静态成员会随着类的加载而加载,如果将所有的成员都变成静态的,那么类一加载,静态成员都会进内存,会大量占用内存空间

问题2:那么静态成员都啥时候定义呢?
一般情况下,我们在抽取工具类的时候可以将工具类中的所有成员都定义成静态的

问题3:啥时候定义工具类?
比如我们在写代码的过程中,发现有的功能在反复实现,代码一样,功能一样,此时就可以抽取出来,形成工具类
public class ArraysUtils {
/*
 构造方法用private修饰

 工具类中的成员都是静态的,静态成员都是类名调用,不需要new对象
 所以工具类中的构造方法都是用private修饰

 如果构造方法被private修饰,那么在别的类中,就不能利用构造方法new对象
*/
private ArraysUtils(){

}


//定义一个方法,实现获取int数组最大值
public static int getMax(int[] arr){
  int max = arr[0];
  for (int i = 1; i < arr.length; i++) {
      if (max<arr[i]){
          max = arr[i];
      }
  }

  return max;
}
}

public class Test01 {
public static void main(String[] args) {
  int[] arr = {5,3,4,6,7,54,8};
  int max = ArraysUtils.getMax(arr);
  System.out.println("max = " + max);
}
}

public class Test02 {
public static void main(String[] args) {
  int[] arr = {5,4,5,7,8,9};
  int max = ArraysUtils.getMax(arr);
  System.out.println("max = " + max);
}
}

2.可变参数

1.需求:
  定义一个方法,实现n个整数相加
      
2.分析:
  方法参数位置,只明确了参数的类型,但是不明确参数个数,此时就可以定义成可变参数

1介绍和基本使用

1.定义格式:
  数据类型...变量名
      
2.注意:
  a.可变参数的本质是一个数组
  b.参数位置不能连续写多个可变参数,而且当可变参数和其他普通参数一起使用时,可变参数需要放到参数列表最后   
public class Demo01Var {
    public static void main(String[] args) {
        sum(1,2,3,4,5);
        sum1(1,1,2,3,4);
    }

    public static void sum(int...arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum+=arr[i];
        }
        System.out.println(sum);
    }
    
    public static void sum1(int i,int...arr){
        
    }
    
}

可变参数.png

2.字符串拼接

需求一:返回n个字符串拼接结果,如果没有传入字符串,那么返回空字符串""

public class Demo02Var {
    public static void main(String[] args) {
        String result = concat("张无忌", "张翠山", "张三丰", "张三");
        System.out.println("result = " + result);
    }

    public static String concat(String...s){
        String str = "";
        for (int i = 0; i < s.length; i++) {
            str+=s[i];
        }

        return str;
    }
}

需求二:n个字符串进行拼接,每一个字符串之间使用某字符进行分隔,如果没有传入字符串,那么返回空字符串""

比如:concat("-","张三丰","张翠山","张无忌") -> 返回 -> 张三丰-张翠山-张无忌
public class Demo03Var {
    public static void main(String[] args) {
        String result = concat("-", "张三丰", "张翠山", "张无忌");
        System.out.println("result = " + result);
    }

    public static String concat(String regex, String... s) {
        String str = "";
        for (int i = 0; i < s.length; i++) {
            if (i == s.length - 1) {
                str += s[i];
            } else {
                str += s[i] + regex;
            }
        }

        return str;
    }
}

3.递归

1.概述:方法内部自己调用自己
2.分类:
  a.直接递归
    public static void method(){
      method()
    }

 b.间接递归:
   A(){
       B()
   }
   B(){
       C()
   }
   C(){
       A()
   }

3.注意:
  a.递归必须要有出口,否则会出现"栈内存溢出"
  b.递归即使有出口,递归次数不不要太多    
public class Demo01Recursion {
    public static void main(String[] args) {
        method();
    }
    public static void method(){
        method();
    }
}

示例一:需求:利用递归输出3到1

public class Demo02Recursion {
    public static void main(String[] args) {
        method(3);
    }

    public static void method(int n){
        if (n==1){
            System.out.println(n);
            //结束方法
            return;
        }
        System.out.println(n);
        n--;
        method(n);
    }
}

递归3到1.png

示例二:求n!(n的阶乘)

1.需求:定义一个方法,完成3的阶乘
      3*2*1
2.分析:假如定义一个方法,代表n的阶乘 -> method(n) -> n接收几,就代表几的阶乘
  
  method(1)  1
  method(2)  2*1 -> 2*method(1)
  method(3)  3*2*1 -> 3*method(2)
    
  method(n) -> n*method(n-1)
public class Demo03Recursion {
    public static void main(String[] args) {
        int method = method(3);
        System.out.println("method = " + method);
    }

    public static int method(int n){
       if (n==1){
           return 1;
       }
       return n*method(n-1);
    }
}

递归n!.png

示例三:计算斐波那契数列(Fibonacci)的第n个值

不死神兔
故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。
在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,一年内没有发生死亡
问:一对刚出生的兔子,一年内繁殖成多少对兔子? 

规律:一个数等于前两个数之和,比如: 1 1 2 3 5 8 13 21 34 55....

递归.斐波那契数列.png

1.假设:定义一个方法,叫做method,参数传递month,代表月份
    
2.分析:
  method(1)     1
  method(2)     1
  method(3)     2 -> method(1)+method(2)
  method(4)     3 -> method(2)+method(3)
  method(5)     5 -> method(3)+method(4)   
      
  method(n) -> method(n-2)+method(n-1)
public class Demo04Recursion {
    public static void main(String[] args) {
        int method = method(12);
        System.out.println("method = " + method);
    }

    public static int method(int n){
       if (n==1 || n==2){
           return 1;
       }
       return method(n-1)+method(n-2);
    }
}

4.数组常见算法

1.数组翻转

1.概述:数组对称索引位置上的元素互换

数组翻转.png

public class Demo01Reverse {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7};
        for (int min = 0,max = arr.length-1;min<max;min++,max--){
            int temp = arr[min];
            arr[min] = arr[max];
            arr[max] = temp;
        }

        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}

2.冒泡排序

 数组的排序,是将数组中的元素按照大小进行排序,默认都是以升序的形式进行排序,数组排序的方法很多,我们讲解的是数组的冒泡排序。

  排序,都要进行数组 元素大小的比较,再进行位置的交换。冒泡排序法是采用数组中相邻元素进行比较换位。
  arr[i](前一个元素)   arr[i+1](后一个元素)
public class Demo02Bubble {
    public static void main(String[] args) {
        //定义一个数组,长度为5,最大索引为4
        int[] arr = {5,4,3,2,1};

        /*
           第一圈
             越界原因:当i变化到4的时候-> arr[4]>arr[5] -> 直接操作了5索引,所以越界了
             越界解决:我们可以让arr.length-1
                     如果arr.length-1-> 比较就是i<4 -> 此时i最大可以变化到3
                     当i变化到3时 -> arr[3]>arr[4] -> 正好是最后两个元素进行比较
         */
        /*for (int i = 0; i < arr.length-1-0; i++) {
            if (arr[i]>arr[i+1]){
                int temp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = temp;
            }
        }*/

        //第二圈
        /*for (int i = 0; i < arr.length-1-1; i++) {
            if (arr[i]>arr[i+1]){
                int temp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = temp;
            }
        }*/

        //第三圈
        /*for (int i = 0; i < arr.length-1-2; i++) {
            if (arr[i]>arr[i+1]){
                int temp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = temp;
            }
        }*/

        //第四圈
        /*for (int i = 0; i < arr.length-1-3; i++) {
            if (arr[i]>arr[i+1]){
                int temp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = temp;
            }
        }*/


        /*
           外层循环代表比较了几圈
           n-1圈
         */
        for (int j = 0; j < arr.length-1; j++) {
            /*
              内层循环代表每一圈比较的次数
              每圈都少比较一次
             */
            for (int i = 0; i < arr.length-1-j; i++) {
                if (arr[i]>arr[i+1]){
                    int temp = arr[i];
                    arr[i] = arr[i+1];
                    arr[i+1] = temp;
                }
            }
        }


        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
    }
}

3.二分查找

1.前提:数组中的数据必须是有序的
2.查询思想:
  a.老式查询:遍历数组,一个一个比较 -> 查询效率慢
  b.二分查找:每次找中间索引对应的元素进行比较查询(每一次查询少一半数据)

二分查找.png

public class Demo03Binary {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,9};
        int index = binary(arr, 60);
        System.out.println(index);
    }

    public static int binary(int[] arr,int data){
        //定义三个变量,分别代表最大索引,最小索引,中间索引
        int min = 0;
        int max = arr.length-1;
        int mid = 0;
        //查找
        while(min<=max){
            mid = (min+max)/2;
            if (data>arr[mid]){
                min = mid+1;
            }else if(data<arr[mid]){
                max = mid-1;
            }else{
                return mid;
            }
        }

        return -1;
    }
}

5.对象数组

1.需求:定义一个长度为3的数组,存储3个Person对象,遍历数组,将三个Person对象中的属性值获取出来
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class Demo01ObjectArray {
    public static void main(String[] args) {
        /*
           Person p = new Person();

           1.定义一个存储int型数据的数组:int[]
           2.定义一个存储double型的数组:double[]
           3.定义一个存储String型的数组:String[]
           4.定义一个存储Person型的数组:Person[]
         */
        //定义数组
        Person[] arr = new Person[3];

        //创建三个对象
        Person p1 = new Person("金莲",26);
        Person p2 = new Person("涛哥",18);
        Person p3 = new Person("张三",20);

        //将三个对象保存到数组中
        arr[0] = p1;
        arr[1] = p2;
        arr[2] = p3;

        /*
           遍历
           当i = 0  arr[0] 就是 p1对象
           当i = 1  arr[1] 就是 p2对象
           当i = 2  arr[2] 就是 p3对象
         */
        for (int i = 0; i < arr.length; i++) {
            //Person p = arr[i];
            System.out.println(arr[i].getName()+"..."+arr[i].getAge());
        }
    }
}

对象数组.png

练习

(1)定义学生类Student

	声明姓名和成绩成员变量

(2)测试类ObjectArrayTest的main中创建一个可以装3个学生对象的数组,并且按照学生成绩排序,显示学生信息
public class Student {
    private String name;
    private int score;

    public Student() {
    }

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

public class Demo02ObjectArray {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("金莲",26);
        students[1] = new Student("大郎",50);
        students[2] = new Student("涛哥",18);

        for (int j = 0; j < students.length-1; j++) {
            for (int i = 0; i < students.length-1-j; i++) {
                if (students[i].getScore()>students[i+1].getScore()){
                    Student temp = students[i];
                    students[i] = students[i+1];
                    students[i+1] = temp;
                }
            }
        }

        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i].getName()+"..."+students[i].getScore());
        }
    }
}

6.方法参数

1.基本数据类型做方法参数传递

基本类型做方法参数传递,传递的是值,不是变量本身
方法运行:压栈
方法运行完毕:弹栈 -> 释放栈内存
public class Demo01Param {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        method(a,b);
        System.out.println(a);//10
        System.out.println(b);//20
    }
    public static void method(int a,int b){
        a+=10;
        b+=20;
        System.out.println(a);//20
        System.out.println(b);//40
    }
}

基本数据类型做方法参数.png

2.引用数据类型做方法参数传递

引用数据类型做方法参数传递时,传递的是地址值
public class Demo02Param {
    public static void main(String[] args) {
        int[] arr = {10,20};
        method(arr);
        System.out.println(arr[0]);//20
        System.out.println(arr[1]);//40
    }

    public static void method(int[] arr){
        arr[0]+=10;
        arr[1]+=20;
        System.out.println(arr[0]);//20
        System.out.println(arr[1]);//40
    }
}

引用数据类型做方法参数.png

7.命令行参数

通过命令行给main方法的形参传递的实参称为命令行参数

main方法参数.png

public class TestCommandParam{
	//形参:String[] args
	public static void main(String[] args){
		for(int i=0; i<args.length; i++){
			System.out.println("第" + (i+1) + "个参数的值是:" + args[i]);
		}
	}
}

运行命令:

java TestCommandParam
java TestCommandParam 1 2 3
java TestCommandParam hello atguigu
1700224698946

命令行参数.png

8.其他操作

1.快速生成方法

1.初学者要求先定义,再调用;不是初学者,就可以先调用,再定义方法
  a.快捷键:alt+回车
      
2.快速将一段代码抽取到一个方法中:
  a.选中要抽取的方法
  b.按ctrl+alt+m      

2.debug调试

1.概述:调试代码的一种手段
    
2.作用:
  a.能清楚的看到每个变量在代码执行过程中的变化
  b.找错
      
3.使用:
  a.在想要开始debug的那一行左边点击一下,出现红色小圆点(断点)
  b.右键-> 点击debug    

debug1.png

debug2.png

4.继承

1.继承

1.什么是继承

1.父类怎么形成的:我们的定义了多个类,发现这些类中有很多重复性的代码,我们就定义了一个父类,将相同的代码抽取出来放到父类中,其他的类直接继承这个父类,就可以直接使用父类中的内容了

2.怎么去继承: extends
   子类 extends 父类

3.注意:
  a.子类可以继承父类中私有和非私有成员,但是不能使用父类中私有成员
  
  b.构造方法不能继承

4.继承怎么学:
   a.继承不要从是否"拥有"方面来学习
      要从是否能"使用"方面来学习
1702867642528

2.继承如何使用

1.定义一个父类,在其中定义重复性的代码
2.定义一个子类继承父类 -> extends
  子类 extends 父类
3.创建子类对象,直接使用父类中非私有成员    
public class Employee {
    String name;
    int age;

    public void work(){
        System.out.println("工作");
    }

    private void eat(){
        System.out.println("员工要干饭");
    }
}

public class Teacher extends Employee{

}

public class Manager extends Employee{
}

public class Test01 {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.name = "涛哥";
        teacher.age = 18;
        System.out.println(teacher.name+"..."+teacher.age);
        teacher.work();
        //teacher.eat();子类继承父类之后不能使用父类私有成员,只能使用父类非私有成员

        System.out.println("============");

        Manager manager = new Manager();
        manager.name = "金莲";
        manager.age = 18;
        System.out.println(manager.name+"..."+manager.age);
        manager.work();
    }
}

3.继承中,成员变量和成员方法的访问特点

3.1 成员变量

1 子类和父类中的成员变量不重名:

public class Fu {
    int numFu = 100;
}

public class Zi extends Fu{
    int numZi = 10;
}
public class Test01 {
    public static void main(String[] args) {
        //创建父类对象
        Fu fu = new Fu();
        System.out.println(fu.numFu);//父类中的numFu
        //System.out.println(fu.numZi);//不能直接调用子类特有的成员

        System.out.println("=================");
        //创建子类对象
        Zi zi = new Zi();
        System.out.println(zi.numZi);
        System.out.println(zi.numFu);//继承了父类,可以使用父类中非私有成员
    }
}

总结:看等号左边是谁,先调用谁中的成员  
    如果等号左边是父类类型,只能调用父类中的成员变量,如果等号左边是子类类型,既能调用子类的,还能调用父类中继承过来的非私有成员

2.子类和父类中的成员变量重名

public class Fu {
    int numFu = 100;

    int num = 10000;
}
public class Zi extends Fu{
    int numZi = 10;

    int num = 1000;
}

public class Test01 {
    public static void main(String[] args) {
        //创建父类对象
        Fu fu = new Fu();
        System.out.println(fu.numFu);//父类中的numFu
        //System.out.println(fu.numZi);//不能直接调用子类特有的成员
        System.out.println(fu.num);//父类的

        System.out.println("=================");
        //创建子类对象
        Zi zi = new Zi();
        System.out.println(zi.numZi);
        System.out.println(zi.numFu);//继承了父类,可以使用父类中非私有成员
        System.out.println(zi.num);//子类的
    }
}

总结:继承前提下,成员变量访问特点口诀:

​ 看等号左边是谁,先调用谁中的成员,子类没有,找父类

3.2 成员方法

public class Fu {
    public void methodFu(){
        System.out.println("我是父类中的methodFu");
    }

    public void method(){
        System.out.println("我是父类中的method方法");
    }
}
public class Zi extends Fu{
    public void methodZi(){
        System.out.println("我是子类中的methodZi方法");
    }

    public void method(){
        System.out.println("我是子类中的method方法");
    }
}
public class Test01 {
    public static void main(String[] args) {
        Fu fu = new Fu();
        fu.methodFu();
       // fu.methodZi(); 不能直接调用子类特有的方法
        fu.method();//父类中的method方法

        System.out.println("=====================");
        Zi zi = new Zi();
        zi.methodZi();
        zi.methodFu();//继承父类之后,能调用父类非私有成员
        zi.method();//子类中的method方法

        System.out.println("===================");

        Fu fu1 = new Zi();
        fu1.method();//调用的是子类中的method方法
    }
}

成员方法:看new的是谁,先调用谁中的方法,子类没有,找父类

继承中,成员变量访问特点:看等号左边是谁,先调用谁中的成员变量

​ 成员方法访问特点:看new的是谁,先调用谁中的方法

4.方法的重写

1.概述:子类中有一个和父类方法名以及参数列表相同的方法
2.前提:继承
3.访问:看new的是谁,先调用谁中的,如果new的是子类,调用调用子类重写的方法,子类没有,找父类
4.检测是否为重写方法:在该方法上写
  @Override  
public class Fu {
    public void methodFu(){
        System.out.println("我是父类中的methodFu方法");
    }
    public void method(){
        System.out.println("我是父类中的method方法");
    }
}
public class Zi extends Fu{
    public void methodZi(){
        System.out.println("我是子类中的methodZi方法");
    }

    @Override
    public void method(){
        System.out.println("我是子类中的method方法");
    }
public class Test01 {
    public static void main(String[] args) {
        Fu fu = new Fu();
        fu.methodFu();//自己的methodFu方法
        fu.method();//new的是父类对象,那么调用的就是父类中的method

        System.out.println("================");

        Zi zi = new Zi();
        zi.methodZi();
        zi.methodFu();
        zi.method();//子类中的method方法
    }
}

4.1.注意事项

1.子类重写父类方法之后,权限必须要保证大于等于父类权限(权限指的是访问权限)
  public -> protected -> 默认 -> private
2.子类方法重写父类方法,方法名和参数列表要一样
3.私有方法不能被重写,构造方法不能被重写,静态方法不能被重写
4.子类重写父类方法之后,返回值类型应该是父类方法返回值类型的子类类型    
public class Fu {
    public void methodFu(){
        System.out.println("我是父类中的methodFu方法");
    }
    public void method(){
        System.out.println("我是父类中的method方法");
    }

    void method01(){

    }

   /* public static void method02(){

    }*/

    public Fu method03(){
        return null;
    }
}
public class Zi extends Fu{
    public void methodZi(){
        System.out.println("我是子类中的methodZi方法");
    }

    @Override
    public void method(){
        System.out.println("我是子类中的method方法");
    }

    @Override
   public void method01(){

    }

   /* public static void method02(){

    }*/

    @Override
    public Zi method03(){
      return null;
    }
}

4.2.使用场景

1.使用场景:功能升级改造,子类需要对父类中已经实现好的功能进行重新改造

方法重写使用场景.png

public class OldPhone {
    public void call(){
        System.out.println("打电话");
    }

    public void message(){
        System.out.println("发短信");
    }

    public void show(){
        System.out.println("显示手机号");
    }
}
public class NewPhone extends OldPhone{
    public void show(){
        System.out.println("显示手机号");
        System.out.println("显示归属地");
    }
}

public class Test01 {
    public static void main(String[] args) {
        NewPhone newPhone = new NewPhone();
        newPhone.call();
        newPhone.message();
        newPhone.show();
    }
}

2.super和this

1.继承中构造方法的特点

1.注意:new子类对象时,会先初始化父类(先走父类无参构造方法)
2.原因:
  每个构造方法的第一行,默认都会有一个super(),不写jvm自动提供一个
  super()代表的是父类无参构造      
public class Fu {
    public Fu(){
        System.out.println("我是父类中的无参构造");
    }
}

public class Zi extends Fu{
    public Zi(){
        //super();
        System.out.println("我是子类中的无参构造");
    }

    public Zi(int i){
        //super();
        System.out.println("我是子类中的有参构造");
    }
}
public class Test {
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println("===========");
        Zi zi1 = new Zi(10);
    }
}

2.super和this的具体使用

2.1 super的具体使用

1.概述:代表的是父类引用
2.作用:可以调用父类中的成员
3.使用:
  a.调用父类构造方法-> 在子类中的构造中写
    super() -> 调用父类无参构造
    super(实参)  -> 调用父类有参构造
      
  b.调用父类成员变量:
    super.成员变量名
        
  c.调用父类成员方法:
    super.成员方法名(实参)
public class Fu {
    int num = 10;
    public Fu(){
        System.out.println("我是父类中的无参构造");
    }

    public Fu(int data){
        System.out.println("我是父类中的有参构造");
    }

    public void method(){
        System.out.println("我是父类中的method方法");
    }
}

public class Zi extends Fu{
    int num = 100;
    public Zi(){
        super();//调用父类中的无参构造
        System.out.println("我是子类中的无参构造");
    }

    public Zi(int num){
        super(10);//调用父类的有参构造
        System.out.println("我是子类中的有参构造");
    }

    public void method(){
        super.method();//调用父类的method方法
        System.out.println("我是子类中的method方法");
        System.out.println(num);//子类自己的
        System.out.println(super.num);//调用父类的num
    }
}

public class Test01 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        System.out.println("============");
        Zi zi1 = new Zi(10);
        System.out.println("============");
        Zi zi2 = new Zi();
        zi2.method();

    }
}

2.2 this的具体使用

1.this概述:代表的是当前对象(哪个对象调用的this所在的方法,this就代表哪个对象)
2.作用:
  a.区分重名的成员变量和局部变量
  b.调用当前对象中的成员
3.使用:
  a.调用当前对象的构造:在构造中写
    this():调用当前对象的无参构造
    this(实参):调用当前对象的有参构造
  b.调用当前对象的成员变量:
    this.成员变量名
  c.调用当前对象的成员方法:
    this.成员方法名(实参)
4.注意:
  不管是super还是this,只要在构造中使用,都必须在第一行,所以二者不能同时手写出来
public class Person {
    int num = 10;
    public Person(){
        //this(10);
        System.out.println("我是Person中的无参构造");
    }

    public Person(int data){
        //super();super和this不能同时再构造中出现
        this();
        System.out.println("我是Person中的有参构造");
    }

    public void method(){
        int num = 20;
        System.out.println(num);//20
        System.out.println(this.num);//10
        this.method01();
        System.out.println("我是Person类中的method方法");
    }

    public void method01(){
        System.out.println("我是Person类中的method01方法");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println("========");
        Person person1 = new Person(10);
        System.out.println("========");
        Person person2 = new Person();
        person2.method();
    }
}

3.继承的特点

1.继承只支持单继承,不能多继承
  public class A extends B,C{}  -> 错误
2.继承支持多层继承
  public class A extends B{}
  public class B extends C{}
3.一个父类可以有多个子类
  public class A extends C{}
  public class B extends C{}

4.构造方法不能继承,也不能重写
  私有方法可以继承,但是不能被重写
  静态方法可以继承,但是不能被重写
public class Fu {
    public void method01(){
        System.out.println("method01方法");
    }

    private void method02(){
        System.out.println("method02方法");
    }

    public static void method03(){
        System.out.println("method03方法");
    }
}

public class Zi extends Fu{
    @Override
    public void method01(){
        System.out.println("重写的method01方法");
    }

/*    @Override
    private void method02(){
        System.out.println("method02方法");
    }*/
}

public class Test01 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method03();
        Zi.method03();
    }
}

4.问题:如何为父类中private的成员变量赋值(经验值)

4.1.利用set赋值

public class Employee {
    private String name;
    private int age;

    public Employee() {
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void work(){
        System.out.println("工作");
    }
}

public class Teacher extends Employee{
}
        Teacher teacher = new Teacher();
        teacher.setName("涛哥");
        teacher.setAge(18);
        System.out.println(teacher.getName()+"..."+teacher.getAge());

4.2.利用构造方法赋值

public class Employee {
    private String name;
    private int age;

    public Employee() {
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void work(){
        System.out.println("工作");
    }
}

public class Manager extends Employee{
    public Manager() {
    }

    public Manager(String name, int age) {
        super(name, age);
    }
}
        Manager manager = new Manager("金莲", 24);
        System.out.println(manager.getName()+"..."+manager.getAge();

public class Test01 {
public static void main(String[] args) {
Teacher t1 = new Teacher("涛哥", 18);
System.out.println(t1.getName()+"..."+t1.getAge());
}
}

5.抽象

抽象类.png

1.抽象的介绍

   1.抽象类怎么来的?
     抽取共性方法,放到父类中,发现方法没法实现,因为每个子类对此方法的实现方式细节不一样
此时方法体说不清道不明,可以定义成抽象方法
    抽象方法所在的类一定是抽象类
   2.关键字: abstract
   3.抽象方法:
      修饰符 abstract 返回值类型 方法名(参数);
   4.抽象类:
       public  abstract class 类名{}
   5.注意:
       a.抽象方法所在的类一定是抽象类
       b.抽象类中不一定非得有抽象方法
       c.子类继承父类之后,需要重写父类
          中所有的抽象方法,不然编译报错
       d.抽象类不能new对象,只能通过new子类对象调动重写方法
           
   6.可以将抽象类看成是一类事物的标准,要求只要是属于这一类的,都必须要拥有抽象类中的方法,必须要给我实现,怎么证明拥有了,怎么证明实现了呢?-> 重写
     至于这个方法怎么实现,就看子类重写之后怎么写方法体了
public abstract class Animal {
   public abstract void eat();
   public abstract void drink();
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    @Override
    public void drink() {
        System.out.println("狗喝水");
    }
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void drink() {
        System.out.println("猫喝水");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
        dog.drink();
        System.out.println("===================");
        Cat cat = new Cat();
        cat.eat();
        cat.drink();
    }
}

2.抽象的注意事项

1.抽象类不能直接new对象,只能创建非抽象子类的对象
2.抽象类中不一定非得有抽象方法,但是抽象方法所在的类一定抽象类
3.抽象类的子类,必须重写父类中的所有抽象方法,否则,编译报错,除非该子类也是抽象类
4.抽象类中可以有成员变量,构造,成员方法
5.抽象类中可以有构造方法,是供子类创建对象时,初始化父类属性使用的    
public abstract class Employee {
    private String name;
    private int age;

    public Employee() {
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public abstract void work();
}
public class Teacher extends Employee{
    public Teacher() {
    }

    public Teacher(String name, int age) {
        super(name, age);
    }

    @Override
    public void work() {
        System.out.println("涛哥在讲java");
    }
}

3.综合练习

某IT公司有多名员工,按照员工负责的工作不同,进行了部门的划分(研发部、维护部)。
研发部(Developer)根据所需研发的内容不同,又分为 JavaEE工程师 、Android工程师 ;
维护部(Maintainer)根据所需维护的内容不同,又分为 网络维护工程师(Network) 、硬件维护工程师(Hardware) 。

公司的每名员工都有他们自己的员工编号、姓名,并要做它们所负责的工作。

工作内容:

- JavaEE工程师: 员工号为xxx的 xxx员工,正在研发电商网站
- Android工程师:员工号为xxx的 xxx员工,正在研发电商的手机客户端软件
- 网络维护工程师:员工号为xxx的 xxx员工,正在检查网络是否畅通
- 硬件维护工程师:员工号为xxx的 xxx员工,正在修复电脑主板

请根据描述,完成员工体系中所有类的定义,并指定类之间的继承关系。进行XX工程师类的对象创建,完成工作方法的调用。

案例继承抽象.png

方式1:利用set赋值

public abstract class Employee {
    private int id;
    private String name;

    public Employee() {
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void work();
}

public abstract class Developer extends Employee{
}

public class JavaEE extends Developer{
    @Override
    public void work() {
        //System.out.println("员工号为:"+getId()+"的"+getName()+"正在开发网站");
        System.out.println("员工号为:"+this.getId()+"的"+this.getName()+"正在开发网站");
    }
}
public class Android extends Developer{
    @Override
    public void work() {
        //System.out.println("员工号为:"+getId()+"的"+getName()+"正在开发app");
        System.out.println("员工号为:"+this.getId()+"的"+this.getName()+"正在开发app");
    }
}
public class Test01 {
    public static void main(String[] args) {
        JavaEE javaEE = new JavaEE();
        javaEE.setId(1);
        javaEE.setName("涛哥");
        javaEE.work();
        System.out.println("===============");
        Android android = new Android();
        android.setId(2);
        android.setName("金莲");
        android.work();
    }
}

方式2:利用构造赋值

public abstract class Employee {
    private int id;
    private String name;

    public Employee() {
    }

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void work();
}

public abstract class Developer extends Employee{
    public Developer() {
    }

    public Developer(int id, String name) {
        super(id, name);
    }
}

public class JavaEE extends Developer{
    public JavaEE() {
    }

    public JavaEE(int id, String name) {
        super(id, name);
    }

    @Override
    public void work() {
        //System.out.println("员工号为:"+getId()+"的"+getName()+"正在开发网站");
        System.out.println("员工号为:"+this.getId()+"的"+this.getName()+"正在开发网站");
    }
}

public class Android extends Developer{

    public Android() {
    }

    public Android(int id, String name) {
        super(id, name);
    }

    @Override
    public void work() {
        //System.out.println("员工号为:"+getId()+"的"+getName()+"正在开发app");
        System.out.println("员工号为:"+this.getId()+"的"+this.getName()+"正在开发app");
    }
}


public class Test02 {
    public static void main(String[] args) {
        JavaEE javaEE = new JavaEE(1, "涛哥");
        javaEE.work();
        System.out.println("===============");
        Android android = new Android(2, "金莲");
        android.work();
    }
}

6.接口

1.接口的介绍

接口.png

2.接口的定义以及使用

1.接口:是一个引用数据类型,是一种标准,规则
2.关键字:
   a.interface 接口
      public interface 接口名{}
   
  b.implements 实现
      实现类 implements 接口名{}

3.接口中可以定义的成员:
   
   a.jdk7以及之前:
     抽象方法: public abstract  -> 即使不写public abstract,默认也有
     成员变量:public static final 数据类型 变量名 = 值-> 即使不写public static final,默认也有
                    final是最终的,被final修饰的变量不能二次赋值,所以我们一般将final修饰的变量视为常量

   b.jdk8:
      默认方法:public default 返回值类型 方法名(形参){}
      静态方法:public static 返回值类型 方法名(形参){}

   c.jdk9开始:
     私有方法:
        private的方法
1.定义接口:
  public interface 接口名{}
2.实现:
  public class 实现类类名 implements 接口名{}
3.使用:
  a.实现类实现接口
  b.重写接口中的抽象方法
  c.创建实现类对象(接口不能直接new对象)
  d.调用重写的方法    
public interface USB {
    public abstract void open();
    public abstract void close();
}

public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("鼠标打开");
    }

    @Override
    public void close() {
        System.out.println("鼠标关闭");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        mouse.open();
        mouse.close();
    }
}

3.接口中的成员

3.1抽象方法

1.定义格式:
  public abstract 返回值类型 方法名(形参);
2.注意:
  不写public abstract 默认也有
3.使用:
  a.定义实现类,实现接口
  b.重写抽象方法
  c.创建实现类对象,调用重写的方法
public interface USB {
    public abstract void open();
    String close();
}
public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("鼠标打开");
    }

    @Override
    public String close() {
        return "鼠标关闭";
    }
}
public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        mouse.open();
        String result = mouse.close();
        System.out.println("result = " + result);
    }
}

3.2默认方法

1.格式:
  public default 返回值类型 方法名(形参){
      方法体
      return 结果
  }
2.使用:
  a.定义实现类,实现接口
  b.默认方法可重写,可不重写
  c.创建实现类对象,调用默认方法     
public interface USB {
   //默认方法
    public default void methodDef(){
        System.out.println("我是默认方法");
    }
}

public class Mouse implements USB {
    @Override
    public void methodDef(){
        System.out.println("我是重写接口中的默认方法");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        mouse.methodDef();
    }
}

3.3静态方法

1.定义格式:
  public static 返回值类型 方法名(形参){
      方法体
      return 结果
  } 

2.使用:
  接口名直接调用
      
public interface USB {
   //默认方法
    public default void methodDef(){
        System.out.println("我是默认方法");
    }

    //静态方法
    public static void methodSta(){
        System.out.println("我是接口中的静态方法");
    }
}
public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        mouse.methodDef();

        System.out.println("=============");

        USB.methodSta();
    }
}

默认方法和静态方法 -> 可以作为临时加的一个小功能来使用

3.4成员变量

1.格式:
  public static final 数据类型 变量名 = 值
2.相关知识点:final
  final代表最终的,被它修饰的变量,不能二次赋值,可以视为常量
3.特点:
  不写public static final 默认也有
4.使用:
  接口名直接调用
5.注意:
  a.被static final修饰的成员变量需要手动赋值
  b.习惯上我们会将static final修饰的成员变量名大写
public interface USB {
    public static final int NUM1 = 100;
    int NUM2 = 200;//不写public static final 默认也有
}
public class Test01 {
    public static void main(String[] args) {
        System.out.println(USB.NUM1);
        System.out.println(USB.NUM2);
    }
}

4.接口的特点

1.接口可以多继承 -> 一个接口可以继承多个接口
  public interface InterfaceA extends InterfaceB,InterfaceC{}
2.接口可以多实现 -> 一个实现类可以实现一个或者多个接口
  public class InterfaceImpl implements InterfaceA,InterfaceB{}
3.一个子类可以继承一个父类的同时实现一个或者多个接口
  public class Zi extends Fu implements  InterfaceA,InterfaceB{}

4.注意:
  继承也好,实现接口也罢,只要是父类中或者接口的抽象方法,子类或者实现类都要重写

当一个类实现多个接口时,如果接口中的抽象方法有重名且参数一样的,只需要重写一次

public interface InterfaceA {
public abstract void method();
}

public interface InterfaceB {
public abstract void method();
}

public class InterfaceImpl implements InterfaceA,InterfaceB{
@Override
public void method() {
System.out.println("重写的method方法");
}
}

当一个类实现多个接口时,如果多个接口中默认方法有重名的,且参数一样的,必须重写一次默认方法

public interface InterfaceA {
public abstract void method();

public default void methodDef(){
System.out.println("我是接口A中的默认方法");
}
}

public interface InterfaceB {
public abstract void method();

/*    public default void methodDef(){
   System.out.println("我是接口B中的默认方法");
}*/
public default void methodDef(int a) {
System.out.println("我是接口B中的默认方法");
}
}

public class InterfaceImpl implements InterfaceA,InterfaceB{
@Override
public void method() {
System.out.println("重写的method方法");
}

/*    @Override
public void methodDef() {
System.out.println("重写后的默认方法");
}*/
}


public class Test01 {
public static void main(String[] args) {
InterfaceImpl anInterface = new InterfaceImpl();
anInterface.methodDef();
anInterface.methodDef(10);
}
}

5.接口和抽象类的区别

相同点:
  a.都位于继承体系的顶端,用于被其他类实现或者继承
  b.都不能new
  c.都包含抽象方法,其子类或者实现类都必须重写这些抽象方法
      
不同点:
  a.抽象类:一般作为父类使用,可以有成员变量,构造,成员方法,抽象方法等
  b.接口:成员单一,一般抽取接口,抽取的都是方法,视为功能的大集合
  c.类不能多继承,但是接口可以

接口和抽象类.png

7.多态

1.面向对象三大特征:封装   继承   多态
2.怎么学:
  a.不要从字面意思上理解多态这两个字,要从使用形式上掌握
  b.要知道多态的好处
  c.要知道多态的前提    

1.多态的介绍

1.前提:
  a.必须有子父类继承或者接口实现关系
  b.必须有方法的重写(没有重写,多态没有意义),多态主要玩儿的是重写方法
  c.new对象:父类引用指向子类对象
    Fu fu = new Zi() -> 理解为大类型接收了一个小类型的数据 ->比如  double b = 10
2.注意:
  多塔下不能直接调用子类特有功能

2.多态的基本使用

public abstract class Animal {
    public abstract void eat();
}

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    //特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    //特有方法
    public void catchMouse(){
        System.out.println("猫会捉老鼠");
    }
}
public class Test01 {
    public static void main(String[] args) {
        //原始方式
        Dog dog = new Dog();
        dog.eat();//重写的
        dog.lookDoor();//特有的

        Cat cat = new Cat();
        cat.eat();//重写的
        cat.catchMouse();//特有的

        System.out.println("==================");
        //多态形式new对象
        Animal animal = new Dog();//相当于double b = 10
        animal.eat();//重写的 animal接收的是dog对象,所以调用的是dog中的eat
//      animal.lookDoor();   多态前提下,不能直接调用子类特有成员

        Animal animal1 = new Cat();
        animal1.eat();//cat重写的


    }
}

3.多态的条件下成员的访问特点

3.1成员变量

public class Fu {
    int num = 1000;
}
public class Zi extends Fu{
    int num = 100;
}
public class Test01 {
    public static void main(String[] args) {
        Fu fu = new Zi();
        System.out.println(fu.num);
    }
}
看等号左边是谁,先调用谁中的成员变量

3.2成员方法

public class Fu {
    int num = 1000;
    public void method(){
        System.out.println("我是父类中的method方法");
    }
}

public class Zi extends Fu{
    int num = 100;

    public void method(){
        System.out.println("我是子类中的method方法");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Fu fu = new Zi();
        System.out.println(fu.num);//父类中的num
        fu.method();//子类中重写的method方法
    }
}

看new的是谁,先调用谁中的成员方法,子类没有,找父类

4.多态的好处(为什么学多态)

1.问题描述:
  如果使用原始方式new对象(等号左右两边一样),既能调用重写的,还能调用继承的,还能调用自己特有的成员
  但是多态方式new对象,只能调用重写的,不能直接调用子类特有的成员,那为啥还要用多态呢?
      
2.多态方式和原始方式new对象的优缺点:
  原始方式:
    a.优点:既能调用重写的,还能调用父类非私有的,还能调用自己特有的
    b.缺点:扩展性差
        
  多态方式:
    a.优点:扩展性强
    b.缺点:不能直接调用子类特有功能
        
      Fu fu = new Zi()
      double b = 10;
      b = 100L;
      
public abstract class Animal {
    public abstract void eat();
}

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    //特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    //特有方法
    public void catchMouse(){
        System.out.println("猫会捉老鼠");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();//重写的
        dog.lookDoor();//特有的

        //dog = new Cat();
        System.out.println("=============");
        method(dog);

        Cat cat = new Cat();
        method(cat);

       /* houzi houzi = new houzi();
        method(houzi);

        bird bird = new bird();
        method(bird);*/
    }

    public static void method(Dog dog){
        dog.eat();
        dog.lookDoor();
    }

    public static void method(Cat cat){
        cat.eat();
        cat.catchMouse();
    }

   /* public static void method(houzi houzi){
        cat.eat();
        cat.catchMouse();
    }*/
}

public class Test02 {
    public static void main(String[] args) {
        /*
           double b = 10;
           b = 100L;
         */
        Animal animal = new Dog();
        animal.eat();

        animal = new Cat();
        animal.eat();
        System.out.println("=================");

        Dog dog = new Dog();
        method(dog);

        Cat cat = new Cat();
        method(cat);

    }

    /*
       形参传递父类类型,调用此方法父类类型可以接收任意它的子类对象
       传递哪个子类对象,就指向哪个子类对象,就调用哪个子类对象重写的方法
     */
    public static void method(Animal animal){//Animal animal = dog   Animal animal = cat
        animal.eat();
    }
}

形参传递父类类型,调用此方法父类类型可以接收任意它的子类对象
传递哪个子类对象,就指向哪个子类对象,就调用哪个子类对象重写的方法

5.多态中的转型

5.1向上转型

1.父类引用指向子类对象
  好比是: double b = 1;

5.2向下转型

1.向下转型:好比强转,将大类型强制转成小类型
2.表现方式:
  父类类型 对象名1 = new 子类对象() -> 向上转型 -> double b = 1
  子类类型 对象名2 = (子类类型)对象名1 -> 向下转型 -> int i = (int)b
      
3.想要调用子类特有功能,我们就需要向下转型      
public abstract class Animal {
    public abstract void eat();
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    //特有方法
    public void catchMouse(){
        System.out.println("猫会捉老鼠");
    }
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    //特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}

public class Test01 {
    public static void main(String[] args) {
        //多态new对象  向上转型
        Animal animal = new Dog();
        animal.eat();//dog重写的
        //animal.lookDoor();//多态不能调用子类特有功能

        //向下转型
        Dog dog = (Dog) animal;
        dog.eat();
        dog.lookDoor();
    }
}

6.转型可能会出现的问题

1.如果等号左右两边类型不一致,会出现类型转换异常(ClassCastException)
2.解决:
  在向下转型之前,先判断类型
3.怎么判断类型: instanceof
  判断结果是boolean型
    
4.使用:
  对象名 instanceof 类型 -> 判断的是关键字前面的对象是否符合关键字后面的类型
public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }

    //特有方法
    public void lookDoor(){
        System.out.println("狗会看门");
    }
}

public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    //特有方法
    public void catchMouse(){
        System.out.println("猫会捉老鼠");
    }
}

public class Test01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        method(dog);

        System.out.println("===============");

        Cat cat = new Cat();
        method(cat);
    }

    public static void method(Animal animal){//animal = dog    animal = cat
      /*  animal.eat();
        *//*
           这里会出现类型转换异常(ClassCastException)
           原因:当调用method,传递Cat对象时,animal代表的就是cat对象
               此时我们将代表cat对象的animal强转成了dog
               此时等号左右两边类型不一致了,所以出现了类型转换异常
         *//*
        Dog dog = (Dog) animal;
        dog.lookDoor();*/

        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.eat();
            dog.lookDoor();
        }

        if (animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.eat();
            cat.catchMouse();
        }
    }
}

7.综合练习

定义笔记本类,具备开机,关机和使用USB设备的功能。具体是什么USB设备,笔记本并不关心,只要符合USB规格的设备都可以。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守USB规范,不然鼠标和键盘的生产出来无法使用;
进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘

- USB接口,包含开启功能、关闭功能
- 笔记本类,包含运行功能、关机功能、使用USB设备功能
- 鼠标类,要符合USB接口
- 键盘类,要符合USB接口

多态练习.png

public interface USB {
    public abstract void open();
    public abstract void close();
}
public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("鼠标开启");
    }

    @Override
    public void close() {
        System.out.println("鼠标关闭");
    }

    //特有方法
    public void click(){
        System.out.println("来呀,快点我");
    }
}

public class KeyBoard implements USB{
    @Override
    public void open() {
        System.out.println("键盘开启");
    }

    @Override
    public void close() {
        System.out.println("键盘关闭");
    }

    //特有功能
    public void input(){
        System.out.println("来呀,敲我呀!");
    }
}
public class NoteBook {
    //开机
    public void start(){
        System.out.println("开机");
    }

    //使用USB
    /*
       USB usb = mouse  多态
       USB usb = keyBoard 多态
     */
    public void useUSB(USB usb){
        if (usb instanceof Mouse){
            Mouse mouse = (Mouse) usb;
            mouse.open();
            mouse.click();
            mouse.close();
        }else{
            KeyBoard keyBoard = (KeyBoard) usb;
            keyBoard.open();
            keyBoard.input();
            keyBoard.close();
        }
        //usb.open();
        //usb.close();
    }

    //关机
    public void stop(){
        System.out.println("关机");
    }
}

public class Test01 {
    public static void main(String[] args) {
        NoteBook noteBook = new NoteBook();
        Mouse mouse = new Mouse();
        noteBook.start();
        noteBook.useUSB(mouse);
        noteBook.stop();

        System.out.println("===========");
        KeyBoard keyBoard = new KeyBoard();
        noteBook.start();
        noteBook.useUSB(keyBoard);
        noteBook.stop();
    }
}

8.面向对象

1.权限修饰符

1 概述

在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,

  • public:公共的,最高权限,被public修饰的成员,在哪里都能访问

  • protected:受保护的

  • default::默认的 注意 不写权限修饰符就是默认权限,不能直接把default写出来

  • private:私有的,只能在自己的类中直接访问

    我们只需要知道一个成员被这四个权限修饰符修饰在4种情况下能不能访问就行了

2 不同权限的访问能力

public protected default(空的) private
同类 yes yes yes yes
同包不同类 yes yes yes no
不同包子父类 yes yes no no
不同包非子父类 yes no no no

public具有最大权限,private有最小权限

编写代码时,如果没有特殊的考虑,建议这样使用权限:

1.属性:用private -> 封装思想
2.成员方法public -> 便于调用
3.构造public -> 便于new对象

2.final关键字

1.概述:最终的
2.使用:
  a.修饰一个类
  b.修饰一个方法
  c.修饰一个局部变量
  d.修饰一个成员变量
  e.修饰一个对象
      
3.怎么学final:只需要知道被final修饰之后特点是啥即可

1.final修饰类

1.格式:
  public final class 类名{}
2.特点:
  被final修饰的类不能被继承
public final class Animal {
}
public class Dog /*extends Animal*/{
}

2.final修饰方法

1.格式:
  修饰符 final 返回值类型 方法名(形参){
      方法体
      return 结果
  }
2.特点:
  被final修饰的方法,不能被重写
      
3.注意:
  final和abstract不能同时修饰一个方法
public abstract class Animal {
    public final void eat(){
        System.out.println("动物要干饭");
    }

    //public abstract final void drink();
}
public class Dog extends Animal{
/*    public void eat(){
        System.out.println("狗啃骨头");
    }*/

}

3.final修饰局部变量

1.格式:
  final 数据类型 变量名 = 值
2.特点:
  被final修饰的变量不能二次赋值
public class Test01 {
    public static void main(String[] args) {
        final int i = 10;
        //i = 20; 被final修饰的变量不能二次赋值
        
        final int j;
        j = 100;
        //j = 200;
                
    }
}

4.final修饰对象

1.格式:
  final 数据类型 对象名 = new 对象();
2.特点:
  被final修饰的对象,地址值不能改变,但是对象中的属性值可以改变
public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class Test02 {
    public static void main(String[] args) {
        //Person p1 = new Person("金莲",26);
        //System.out.println(p1);//地址值
        //p1 = new Person("涛哥",18);
        //System.out.println(p1);//地址值

        final Person p1 = new Person("金莲",26);
        System.out.println(p1);//地址值
        //p1 = new Person("涛哥",18);
        //System.out.println(p1);//地址值

        p1.setName("大郎");
        p1.setAge(30);
        System.out.println(p1.getName()+"..."+p1.getAge());
    }
}

5.final修饰成员变量

1.格式:
  final 数据类型 变量名 = 值
2.特点:
  a.需要手动赋值
  b.不能二次赋值
public class Student {
    final String name = "广坤";

    public Student() {
    }

    //有参构造现在属于二次赋值了
    /*public Student(String name) {
        this.name = name;
    }*/

    public String getName() {
        return name;
    }
    //set方法现在属于二次赋值了
    /*public void setName(String name) {
        this.name = name;
    }*/
}

3.代码块

1.构造代码块

1.格式:
  {
      代码
  }

2.执行特点:优先于构造方法执行,每new一次,就会执行一次
public class Person {
    public Person(){
        System.out.println("我是无参构造方法");
    }

    //构造代码块
    {
        System.out.println("我是构造代码块");
    }
}
public class Test01 {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
    }
}

2.静态代码块

1.格式:
  static{
      代码
  }

2.执行特点:
  静态代码块优先于构造代码块和构造方法执行的,而且只执行一次
public class Person {
    public Person(){
        System.out.println("我是无参构造方法");
    }

    //构造代码块
    {
        System.out.println("我是构造代码块");
    }

    //静态代码块
    static{
        System.out.println("我是静态代码块");
    }
}
public class Test01 {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
    }
}

3.静态代码块使用场景

如果想让一些数据最先初始化,而且只需要初始化一次,就可以将这些数据放到静态代码块
如javajdbc数据库驱动

第四章.内部类

1.什么时候使用内部类:
  当一个事物的内部,还有一个部分需要完整的结构去描述,而这个内部的完整结构又只为外部事物提供服务,那么整个内部的完成结构最好使用内部类
      
  比如:人类都有心脏,人类本身需要用属性,行为去描述,那么人类内部的心脏也需要心脏特殊的属性和行为去描述,此时心脏就可以定义成内部类,人类中的一个心脏类
      
2.在java中允许一个类的定义位于另外一个类内部,前者就称之为内部类,后者称之为外部类
  class A{
      class B{
          
      }
  }

  类A就是类B的外部类
  类B就是类A的内部类
      
3.分类:
  成员内部类(静态,非静态)
  局部内部类
  匿名内部类(重点)

1 静态成员内部类

1.格式:直接在定义内部类的时候加上static关键字
  public class A{
      static class B{
          
      }
  }

2.注意:
  a.内部类可以定义属性,方法,构造等
  b.静态内部类可以被final或者abstract修饰
    被final修饰之后,不能被继承
    被abstract修饰之后,不能new
  c.静态内部类不能调用外部的非静态成员
  d.内部类还可以被四种权限修饰符修饰
      
3.调用静态内部类成员:
  外部类.内部类 对象名 = new 外部类.内部类()
public class Person {
    public void eat(){
        System.out.println("人要干饭");
    }

    static class Heart{
        public void jump(){
            System.out.println("心脏哐哐哐跳");
        }
    }
}
public class Test01 {
    public static void main(String[] args) {
       // 外部类.内部类 对象名 = new 外部类.内部类()
        Person.Heart heart = new Person.Heart();
        heart.jump();
    }
}

2 非静态成员内部类

1.格式:直接在定义内部类的时候加上static关键字
  public class A{
      class B{
          
      }
  }

2.注意:
  a.内部类可以定义属性,方法,构造等
  b.静态内部类可以被final或者abstract修饰
    被final修饰之后,不能被继承
    被abstract修饰之后,不能new
  c.静态内部类不能调用外部的非静态成员
  d.内部类还可以被四种权限修饰符修饰
      
3.调用非静态内部类成员:
  外部类.内部类 对象名 = new 外部类().new 内部类()
public class Person {
    public void eat(){
        System.out.println("人要干饭");
    }

    class Heart{
        public void jump(){
            System.out.println("心脏哐哐哐跳");
        }
    }
}
public class Test01 {
    public static void main(String[] args) {
       // 外部类.内部类 对象名 = new 外部类().new 内部类()
        Person.Heart heart = new Person(). new Heart();
        heart.jump();
    }
}

外部类的成员变量和内部类的成员变量以及内部类的局部变量重名时,怎么区分?

public class Student {
String name = "金莲";
class Heart{
  String name = "大郎";
  public void display(String name){
      System.out.println(name);//内部类的局部变量
      System.out.println(this.name);//内部类的成员变量
      System.out.println(Student.this.name);//外部类的成员变量
  }
}
}


public class Test02 {
public static void main(String[] args) {
  Student.Heart heart = new Student().new Heart();
  heart.display("涛哥");
}
}

3.局部内部类

3.1.局部内部类基本操作

1.可以定义在方法中,代码块中,构造中
public class Person {
    public void eat(){
        class Heart{
            public void jump(){
                System.out.println("心脏哐哐哐的跳");
            }
        }

        new Heart().jump();
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.eat();
    }
}

3.2.局部内部类实际操作

3.2.1.接口类型作为方法参数传递和返回

1.接口作为方法参数,传递实参时,传递的是实现类对象

2.接口作为返回值类型返回,实际返回的是实现类对象

public interface USB {
    public abstract void open();
}
public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("鼠标打开");
    }
}
public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        method(mouse);
        System.out.println("================");

        USB usb = method01();//USB usb = new Mouse();
        usb.open();
    }

    /*
       接口作为方法参数,传递实参时,传递的是实现类对象
     */
    public static void method(USB usb){//USB usb = mouse -> 多态
        usb.open();
    }

    /*
      接口作为返回值类型返回,实际返回的是实现类对象
    */
    public static USB method01(){
        //Mouse mouse = new Mouse();
        //return mouse;
        return new Mouse();
    }
}

3.2.2.抽象类作为方法参数和返回值

1.抽象类作为方法参数传递,传递实参时,传递的是其子类对象

2.抽象类作为方法返回值类型返回时,实际返回的是其子类对象

public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }
}
public class Test02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        method01(dog);
        System.out.println("=================");
        Animal animal = method02();//Animal animal = new Dog()
        animal.eat();
    }

    public static void method01(Animal animal){//Animal animal = dog
        animal.eat();
    }

    public static Animal method02(){
        return new Dog();
    }
}

3.2.3.普通类做方法参数和返回值

普通类作为方法参数传递,传递的是对象

普通类作为方法返回值返回,返回的是对象

public class Person {
    public void eat(){
        System.out.println("人要干饭");
    }
}

public class Test03 {
    public static void main(String[] args) {
        Person person = new Person();
        method01(person);
        System.out.println("==================");
        Person person1 = method02();//Person person1 = new Person()
        person1.eat();
    }
    public static void method01(Person person){
        person.eat();
    }

    public static Person method02(){
        return new Person();
    }
}

3.2.4.局部内部类实际操作

public interface USB {
    void open();
}

public class Test01 {
    public static void main(String[] args) {
        USB usb = method();//USB usb = new Mouse()
        usb.open();
    }

    public static USB method(){
        //局部内部类
        class Mouse implements USB{

            @Override
            public void open() {
                System.out.println("鼠标打开");
            }
        }

        return new Mouse();
    }
}

4.匿名内部类(重点)

所谓的匿名内部类,可以理解为没有显式声明出类名的内部类

1.问题描述:我们如果想实现接口,简单使用一次抽象方法,我们就需要创建一个实现类,实现这个接口,重写抽象方法,还要new实现类对象,所以我们在想如果就单纯的想使用一次接口中的方法,我们能不能不这么麻烦呢?可以
  a.创建实现类,实现接口
  b.重写方法
  c.创建实现类对象
  d.调用方法
    
2.如果就想单纯的使用一下接口中的方法,我们就没必要经过以上四步了,我们可以四合一
    
3.匿名内部类怎么学:就按照一种格式来学,这一种格式就代表了实现类对象或者子类对象
    
4.格式:
  new 接口/抽象类(){
      重写方法
  }.重写的方法();

  =================================

  类名 对象名 = new 接口/抽象类(){
      重写方法
  }
  对象名.重写的方法();
public interface USB {
    void open();
    void close();
}
public class Test01 {
    public static void main(String[] args) {
        new USB(){

            @Override
            public void open() {
                System.out.println("usb打开了");
            }

            @Override
            public void close() {
                System.out.println("usb关闭了");
            }
        }.open();

        System.out.println("===================");

        USB usb = new USB() {
            @Override
            public void open() {
                System.out.println("USB打开了");
            }

            @Override
            public void close() {
                System.out.println("USB关闭了");
            }
        };
        usb.open();
        usb.close();
    }
}

匿名内部类.png

1.什么时候使用匿名内部类:

​ 当简单调用一次接口中的方法,我们就可以使用匿名内部类

2.将一种格式代表实现类对象或者子类对象来看待,来学习

3.匿名内部类会编译生成的,咱们不要管,我们只需要利用咱们讲的格式去new对象,调用重写的方法即可

4.1 匿名内部类复杂用法_当参数传递

public interface USB {
    void open();
}
public class Test01 {
    public static void main(String[] args) {
        method01(new USB() {
            @Override
            public void open() {
                System.out.println("usb打开了");
            }
        });
    }
    public static void method01(USB usb){
        usb.open();
    }
}

匿名内部类当参数传递.png

4.2 匿名内部类复杂用法_当返回值返回

public interface USB {
    void open();
}

public class Test02 {
    public static void main(String[] args) {
        USB usb = method01();
        usb.open();

    }

    public static USB method01(){
        return new USB() {
            @Override
            public void open() {
                System.out.println("USB打开了");
            }
        };
    }
}

匿名内部类当返回值返回.png

posted @ 2025-03-19 17:20  朱啸毅  阅读(48)  评论(0)    收藏  举报