JavaSE学习笔记-05

房屋出租系统:

 

 

我们通常设置一个模式策略图:

在这个Houserent大包下面建立这四个子小包

 源代码如下:

1.测试类HouseRentApp

2.建立一个House类

package JavaSE练习代码.Houserent.domin;

/**
 * House主类对象
 */
public class House {
   private int id;
   private String name;
   private String phone;
   private String address;
   private int rent;
   private String state;

    public House(int id, String name, String phone, String address, int rent, String state) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.address = address;
        this.rent = rent;
        this.state = state;
    }

    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 String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getRent() {
        return rent;
    }

    public void setRent(int rent) {
        this.rent = rent;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    @Override
    public String toString() {
        return  id +
                "\t" + name +
                "\t"+ phone +
                "\t" + address+
                "\t" + rent +
                "\t" + state ;
    }
}

3.界面展示类:HouseView

package JavaSE练习代码.Houserent.view;

import JavaSE练习代码.Houserent.domin.House;
import JavaSE练习代码.Houserent.service.HouseSevice;

import java.util.Scanner;

/**
 * 1.显示界面
 * 2.接收用户的输入
 * 3.调用HouseSerivce完成对房屋信息的各种操作
 */
public class HouseView {
    private boolean loop=true;
    private int key;
    //new一个HouseSevice对象,并且初始化它的size大小
    private HouseSevice houseSevice=new HouseSevice(10);
    public void exit(){
        Scanner scanner=new Scanner(System.in);
        do {
            System.out.println("请输入(1)表示你确认真的要退出系统");
            int leo=scanner.nextInt();
            if(leo==1){
                loop=false;
            }
        }while (loop);
    }
    /**
     * 显示界面
     * 1.add添加
     * 2.del删除
     * 3.find查找
     * 4.update修改
     * 5.显示房屋列表
     */
    //1.
    public void add(){
        Scanner scanner=new Scanner(System.in);
        System.out.println("===========添加房屋=================");
        System.out.print("姓名:");
        String name=scanner.next();
        System.out.print("电话:");
        String phone=scanner.next();
        System.out.print("地址:");
        String address=scanner.next();
        System.out.print("月租:");
        int rent=scanner.nextInt();
        System.out.print("状态:");
        String state=scanner.next();
        //创建一个新的House对象,但是注意id这个号是系统自动递增分配的
        House house=new House(0,name,phone,address,rent,state);
        if(houseSevice.add(house)){
            System.out.println("添加房屋成功");
        } else {
            System.out.println("添加房屋失败");
        }
    }
    //2.
    public void del(){
        Scanner scanner=new Scanner(System.in);
        System.out.println("===========删除房屋=================");
        System.out.println("请输入删除房屋的编号(-1退出)");
        int delId=scanner.nextInt();
        if(delId==-1){
            System.out.println("放弃删除房屋信息");
            return;//退出方法
        }
        System.out.println("请输入(1)表示确定  输入其他的字符表示放弃删除");
        int choice=scanner.nextInt();
        if(choice==1){
            if(houseSevice.del(delId)){
                System.out.println("删除成功");
            } else {
                System.out.println("对不起,删除失败,该号码不存在");
            }
        } else {
            System.out.println("放弃删除房屋信息");
        }
    }
    //3.
    public void finById(){
        Scanner scanner=new Scanner(System.in);
        System.out.println("===========查找房屋=================");
        System.out.println("请您输入你要查找的房屋编号");
        int id=scanner.nextInt();
        House house=houseSevice.findById(id);
        if(house!=null){
            System.out.println("恭喜您查找成功哦,宝贝");
            System.out.println(house);
        } else {
            System.out.println("查找失败,无此房屋");
        }
    }
    //4.修改
    public void update(){
        Scanner scanner=new Scanner(System.in);
        System.out.println("===========修改房屋=================");
        System.out.println("请您输入你要修改的房屋编号");
        int updateid=scanner.nextInt();
        House house= houseSevice.findById(updateid);
        if(house==null){
            System.out.println("不好意思,没有此房屋,输入错误");
            return;
        }
        System.out.print("姓名("+house.getName()+"):");
        String name=scanner.next();
        if(!"".equals(name)){
            house.setName(name);
        }
        System.out.print("电话("+house.getPhone()+"):");
        String phone=scanner.next();
        if(!"".equals(phone)){
            house.setPhone(phone);
        }
        System.out.print("地址("+house.getAddress()+"):");
        String address=scanner.next();
        if(!"".equals(address)){
            house.setAddress(address);
        }
        System.out.print("租金("+house.getRent()+"):");
        int rent=scanner.nextInt();
        if(rent>0){
            house.setRent(rent);
        }
        System.out.print("状态("+house.getAddress()+"):");
        String state=scanner.next();
        if(!"".equals(state)){
            house.setAddress(state);
        }
    }
    //5.
    public void listHouse(){
        System.out.println("===========房屋列表=================");
        System.out.println("编号\t\t房主\t\t电话\t\t地址\t\t月租\t\t状态(未出租/出租)");
        House[] houses=houseSevice.list();//返回的是这个房屋数组对象
        for (int i = 0; i < houses.length; i++) {
            //如果房屋为空了,那么就应该直接退出for循环
            if(houses[i]==null){
                break;
            }
            System.out.println(houses[i]);
        }
        System.out.println("===========房屋列表显示完毕============");
    }
    /**
     * 显示主菜单
     */
    public void mainMenu(){

        do {
            System.out.println("=========房屋出租系统菜单========");
            /**
             * ctrl+向下箭头:快速复制当前行
             */
            System.out.println("\t\t\t1 新增房屋");
            System.out.println("\t\t\t2 查找房屋");
            System.out.println("\t\t\t3 删除房屋信息");
            System.out.println("\t\t\t4 修改房屋信息");
            System.out.println("\t\t\t5 房屋列表");
            System.out.println("\t\t\t6 退出");
            System.out.println("请输入当前选择数字(1-6)");
            Scanner scanner=new Scanner(System.in);
            key=scanner.nextInt();
            switch (key){
                case 1:
                    add();
                    break;
                case 2:
                    finById();
                    break;
                case 3:
                    del();
                    break;
                case 4:
                   update();
                    break;
                case 5:
                    listHouse();
                    break;
                case 6:
                    exit();
                    System.out.println("退出");
                    loop=false;
                    break;
            }
        }while (loop);
    }
}

4.业务执行逻辑层:HouseService

对于界面的方法逻辑方法进行逻辑的构建:

package JavaSE练习代码.Houserent.service;

import JavaSE练习代码.Houserent.domin.House;

/**
 * 1.响应HouseView的调用
 * 2.完成对房屋信息的各种操作(增删改查:c[creat]r[read]u[update]d[delete])
 */
public class HouseSevice {
    private int houseNums=1;//记录当前有多少个房屋信息
    private int idcounter=1;//记录当前id号是多少,由于我们初始化了一个所以默认从1开始
    private House[] houses;//保存House对象

    //构造器:我们把这个数组大小放到数组中进行初始化
    public HouseSevice(int size){
        houses=new House[size];//当创建HouseService对象时,指定数组大小
        /**
         * 构造器中创建的对象,是初始化的信息。。。是为了测验功能的
         */
        houses[0]=new House(1,"\tjack","110","北京",2000,"未出租");
    }
    //list方法 ,我们返回的是houses对象
    public House[] list(){
        return houses;
    }
    //添加新对象,返回boolean值
    public boolean add(House newhouse){
        //判断是否还能继续添加
        if(houseNums== houses.length){
            System.out.println("数组已满了哦,不可以继续添加");
            return false;
        }
        //把newhouse对象加到数组中
        houses[houseNums++]=newhouse;
        //搞出来一个递加的学号
        newhouse.setId(++idcounter);
        return true;
    }
    //删除对象
    public boolean del(int delId){
        int index=-1;
        for (int i = 0; i < houses.length; i++) {
            if(houses[i].getId()==delId){
                index=i;//记录要删除对象的下标
            }
        }
        if(index==-1){
            return false;
        }
        //进行删除,为防止空指针异常,那么要判断好i的右边范围
        for (int i =index; i <houses.length-1 ; i++) {
            houses[i]=houses[i+1];
        }
        //并且把最后一个搞成null,因为它已经赋给前面了
        houses[houseNums-1]=null;
        //置空之后就可以进行直接
        houseNums--;//减少一个
        /**
         * 可以把上面两句和为一句:house[--houseNums]=null;
         */
        return true;
    }
    //查找房屋的方法
    public House findById(int id){
        for (int i = 0; i < houses.length; i++) {
            if(houses[i].getId()==id){
                return houses[i];
            }
        }
        return null;
    }
}

静态变量Static(类变量):

类变量引入:

注意:类的加载一个类只进行一次,因此静态变量只进行一次的初始化


 

 只要是一个静态的变量,我们通过类实例化出的对象引用,进行访问指向的静态变量都是同一个的。

 类变量的内存布局:

总结:

1.无论静态变量位于方法区还是位于堆空间,记住一点就是静态变量是被所有实例出的对象引用所共享的。(在JDK8以前,静态变量内存空间位于方法区,JDK8之后,是位于堆空间的Class实例对象的尾部的位置。)

解释:

因为Class对象是由类加载信息出的,将加载出的结构信息存储在方法区。这个静态变量是保存在Class实例对象的尾部,Class对象确实在堆中。

 类加载信息可以在堆空间加载出一个Class对象,

2.所以无论它是位于方法区还是堆空间,都是被类Child所有的对象实例所共享的 (即是被类new出来的所有对象的所有对象引用共同指向)

注意:类的加载一个类只进行一次,因此静态变量只进行一次的初始化

 类变量的总结细节:

非静态变量有多种叫法,我们要懂得名字的不同:

 6.

 ——————————————————————————————————————————

 类方法:

下图是测试类的访问:

先创建两个实例化的对象进行访问改变静态变量的值

之后再通过类名进行访问。

 静态方法(类方法)的使用场景:

 

我们不想要创建实例 ,而是直接通过类名去调用某一个方法的时候,我们把该方法作为静态方法。

举个例子:

类方法(静态方法)的使用细节:

this是代表该类的这个实例化出来的对象的引用,然而类方法和类变量(即是静态方法和静态属性变量)的构建是不依赖于对象的,而是通过类的加载信息而加载出来的【但是注意一点,一个类只进行一次的加载,因此静态成员只进行一次的初始化】,将结构的信息存储在方法区,加载出来的Class对象是位于堆空间上的,静态变量和静态方法的地址都是位于Class实例对象的尾部的。因此我们不可以通过this关键字去访问类方法和类属性。

静态方法只能访问静态成员(即是静态变量或静态方法):

n2为静态变量

say为普通成员方法,hi为静态成员方法

 

成员包括方法和属性。

 ————————————————————————————————————————

 类(静态)方法和类(静态)变量的练习

 

依次输出 9 10 11;静态变量count在内存中仅有一份 

对于一个类Test,我们只进行一次的类加载。因此静态成员只进行一次的初始化。

 

 错误点:

id是非静态成员变量,因此我们不可以在静态成员方法中进行访问。

 构造器相当于是一个非静态的成员方法,我们可以进行访问静态的成员和非静态的成员

 

答案是

total==4

错误之处:

 我解释一下:

首先我们知道,能在静态方法中进行访问的一定是静态成员,当然这里就是为了把传进来的total值赋给我们类中的静态成员变量total,但是不可以用this去访问我们的静态成员。因为this代表的是当前对象,this代表的对象的地址是存放在栈空间中的。【静态变量和静态方法的地址都是位于Class实例对象的尾部的但是静态成员的创建是不依赖于对象的,而是通过类的加载信息而加载出来的,将结构的信息存储在方法区,加载出来的Class对象是位于堆空间上的,静态变量和静态方法的地址都是位于Class实例对象的尾部的因此我们不可以通过this关键字去访问类方法和类属性。

 我们只可以用类名进行访问来解决这个问题。。。。。PS:如图

 深入理解main方法语法

解释上面几点结论:

 1.main方法是Java虚拟机进行调用的。

 2.因为Java虚拟机调用main方法的时候,它俩不在同一个类中,所以main方法需要public修饰

 3.因为Java虚拟机调用main方法的时候不创建对象直接调用,因此必须是static类型

 4.执行程序的时候输入的参数就是args数组中的内容。

 5.由于该main方法是Java虚拟机进行调用的,所以不需要返回什么,所以无返回值,是void

 注意:

 如图:

 

——————————————————————————————————————

如何在idea上传递参数给我们的main方法?

 

 代码块

基本语法:

 使用场景:

 重点:

 在测试类main方法中创建对象

无论调用哪一个构造器,都会优先调用代码块的内容

 其实代码块就是对构造器进行协助操作,

当构造器发生重载时,如图:多个构造器的代码重复的过多。我们可以把这些重复的代码放到代码块中,在new一个对象的时候,调用代码块会优先于执行构造器

 代码块使用细节(重点):

1.

一个类只进行一次类的加载,因此,一个静态的成员只进行一次的初始化。因此,静态代码块只执行一次。

2. 

 3.

举例子说明上面三条细节:

 创建一个对象实例之后,我们可知,类AA的信息会随着类加载到方法区。。。。

类加载的三种情况:并且记住一个类只可以进行一次的类加载,因此静态成员只可以被初始化一次

——————————————————————————————————————

1.通过该类名去new,创建出来一个实例化对象引用

2.创建子类对象实例

继承的本质是先加载父类再加载子类(先有爸爸再有儿子),先父类的信息加载到方法区在加载子类的信息 

 3.如图使用类的静态成员 用类名直接调用静态成员

 new出来两个对象但是类只加载一次(因为一个类只被加载一次),因此静态代码块只执行一次

 

 

普通代码块在new,就是创建对象实例的时候,会被隐式的调用,被加载一次就会被调用一次,但是如果只是用类名调用静态成员的时候,不会调用普通的代码块。。。。。

普通代码块的调用与否不取决于类加载,而是取决于是否创建实例对象。

可以理解为普通代码块就是一个构造器的补充。

并且注意一点,静态代码块只能被类加载调用一次。无论它是通过这个相同的类new出了多少个对象,记住一点就是这个类只进行一次的加载。因此只要是有关静态的成员都只会进行一次的初始化,即是只进行一次的执行调用。

————————————————————————————————————

类加载的方式有两种:

1.通过这个类名去new,创建了一个实例化对象

2.使用类名直接调用静态成员

PS:类加载子类的时候,先类加载父类的信息再类加载子类的信息

3.创建子类实例对象引用也是会让父类进行类加载的

 ——————————————————————————————————————

 代码块重点:调用顺序

 第一个:

 优先级一样,则按先后顺序进行调用

第二个点:

 调用顺序:

 

构造器的调用优先级是最低的 

 

调用顺序从前到后1 2 3进行顺序执行 

 倘若优先级相等,那么谁在前面那么就先执行谁。。。。

结论:

 注意一个点就是:当一个类继承了一个父类之后:

我们对于一个构造器第一行都会默认是调用父类的无参构造器的,倘若说父类的有参构造器覆盖了父类的无参构造器,那么我们就要用super(父类构造器的参数)进行调用。

解释一下为什么:继承这个东西,子类继承了父类除构造器之外的所有东西,但是构造器也会进行调用父类的构造器,所以出现了super调用构造器这一现象。 

 

 调用顺序分析:

第一次new对象的之前,第一步要进行的是类加载,但是代码中并没有静态的成员,因此这一步直接省略过去。

我们new了一个实例对象,调用无参构造器,由于BBB继承了AAA所以这个无参构造器是默认带有一个super(),因为父类是有一个隐藏的无参构造器的。。。。。并且第二步是调用普通代码块(只要对象实例化一次,就调用一次普通代码块),调用AAA类的无参构造器,AAA也有一个super()默认调用父类Object的无参构造器,以及第二步调用AAA本类的普通代码块(但是没有)所以执行顺序一目了然了就。。。。。。。

 最难调用顺序:

 

当我们在main方法中进行测试,即是new B02();创建一个对象

当我们通过一个类名第一次去new一个对象实例的时候我们要进行的步骤为

1.进行类的加载 ,由于静态代码块的调用是通过类加载进行调用的,因此可知,静态代码块是优先被调用的 。如果一个类继承的有父类,那么我们可知,先进行父类的加载,再进行子类的加载。直到第一步类的加载执行完毕之后,我们才能执行第二步new一个对象

2.创建对象 

 代码如下:

 

public B02(){

System.out.println("B02的构造器");

}上图少截取的一段代码

__________________________________________________________________

 顺序如图:

 挺多的,但是还是要总结一下上面这道题,,:

1.当我们new出来一个子类B02的实例对象的时候,我们要先明白new一个对象时的步骤顺序

值得我们记住的是这一次new对象实例,是我们通过这个类名进行的第一次new对象实例,因此必须进行类的加载,类的加载完成之后,我们才可以进行第二步new对象实例

步骤是这样的:(一定要记住一点,当执行完第一步之后,我们才可以执行第二个步骤的调用)

第一步:先进行类的加载。类的加载让我们明白,我们必须优先把静态的先进行调用完毕,无论是父类还是子类的静态的东西ok,

那么对于静态代码块和静态的成员来说,优先级是一致的,所以我们要按先后顺序进行调用执行。

记住一个顺序,先执行父类的再执行子类的。所以我们可以知道,当父类的所有静态的东西执行完了之后,我们才可以执行子类静态的东西。当父类与子类静态的东西执行完了之后,我们才可以进行下一步步骤。

第二步:创建对象。我们由图可知:new B02();调用的是子类的无参构造器,我们要记住一点,当父类的无参构造器没被覆盖的时候,

我们要分析出 子类构造器是隐藏两步和显示的一步:

1.super()调用父类的无参构造器  2.调用子类普通代码块。

以及显示的第三步 执行子类构造器显示内容

注意一点:只有当第一步调用父类无参构造器执行完之后,我们才会执行第二步 执行完第二步才会执行第三步:执行子类的构造器

ok执行第一步:如下:

当调用父类的无参构造器也是隐藏两步和显示的一步:

1.调用父类Object的无参构造器(即是super();调用)

2.调用父类的普通代码块

以及显示的第三步 执行父类构造器的显示内容

当父类这两步执行完了之后,然后就要执行显示的第三步 执行父类构造器的显示内容

当以上三步执行完之后,我们才会开始执行子类的第二步,因为这三步都是子类第一步super();扩展出来的

——————————————————————————————————————

(PS:当父类的无参构造器被覆盖之后,我们必须只能把子类的无参构造器改为有参构造器,并且用super(父类构造器的参数);调用父类构造器)

 再看一次吧:

 

代码块练习题:

答案:

使用类名进行调用,也是产生类加载,优先级相同,按顺序执行,当静态的东西执行完之后才会在main方法中打印输出结果。并且我们要知道,static静态代码块只可以执行一次。

输出如图所示:

 

记住一点:在一个类中只要是不加static的,其他的都是普通代码块

例如: 

A b=new A(); 这就是一个普通代码块。。。。。所以题中的 Sample类new对象也是一个普通代码块

 答案:

 单列设计模式:

饿汉式

 如何保障只创建一个对象?

 这就要用到单例设计模式了:

static静态的东西是类加载中就完成了,我们可以知道:new一个对象实例的时候分为两个步骤:

第一步:类加载

第二步:创建对象

静态的对象只可以类加载一次,因此每一次都是同一个女朋友。

 测试类:

 

私有化构造器是为了防止外部类直接进行创建对象 

为什么叫做饿汉式?

因为还没有拿去用这个对象的时候就已经static类加载完成了。。有可能创建了一个对象,但是后来我们并没有去使用它,而是把它浪费了,这就是饿汉行为。

这就是饿汉式的意义所在。。

懒汉式:

 

但是当我们再一次进行调用的时候,但是还是返回的是上一个对象

这就是懒汉。只会创建一次对象,不会造成资源的浪费。。。。。

 

 

线程安全问题依旧存在:

 当三个线程同时进来的时候,我们在那一个时间点三个线程就会创建三个对象,但是到最后只会保留一个对象。

经典的饿汉单例模式:

 记住一点就行,

当我们new一个对象的时候,要进行两步。第一步是先进行类加载,之后第二步再进行创建对象

但是当类名访问静态成员的时候,只有一步类加载。。。。无创建对象的过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值