周测——JavaE+编程题+设计模式

目录

 

简答题:

1.请你谈一下面向对象的"六原则一法则"。

2.请你解释一下,内存中的栈(stack)、堆(heap) 和静态区(static area) 的用法。

3.请谈一谈,什么情况下会发生死锁?解决死锁的策略有哪些?

编程题:(来自力扣)

1.一年中的第几天 (将自己的分析思路写出)

2.编写一个加密程序。

3.在开发过程你用到过那些设计模式?用在什么场合?除单例模式外写出其他一种你常用的设计模式?


简答题:

1.请你谈一下面向对象的"六原则一法则"。

六原则主要指单一职责原则、开闭原则、依赖倒转原则、里氏替换原则、接口隔离原则、合成聚合复用原则。

  • 单一职责原则:一个类只做它该做的事情,不要赋予过多的功能。

  • 开闭原则:软件实体应当对拓展开放,对修改关闭。当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码。要做到开闭有两个要点:

    • 系统需要有抽象类或接口

    • 封装可变性,将系统中的各种可变因素封装到一个继承结构中。

  • 依赖倒转原则:面向接口编程。在定义方法时,尽量使用抽象类型而不使用具体类型,因为抽象类可以被他的任何子类代替。

  • 里氏替换原则:任何时候都可以用子类型替换掉父类型。简单的说就是能用父类型的地方就一定能使用子类型。

    • 作用:里氏替换原则可以检查继承关系是否合理,如果一个继承关系违背了里氏替换原则,那么这个继承关系一定是错误的,需要对代码进行重构。

    • 需要注意的是:子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题

  • 接口隔离原则:接口要小而专,不能大而全。

  • 合成聚合复用原则:类与类之间简单的说有三种关系,Is-A关系、Has-A关系、Use-A关系,分别代表继承、关联和依赖。优先考虑Has-A关系而不是Is-A关系复用代码。任何时候都不要继承工具类,工具是可以拥有并可以使用的,而不是拿来继承的。

一法则主要指迪米特法则。

迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。

迪米特法则简单的说就是如何做到"低耦合",门面模式和调停者模式就是对迪米特法则的践行。

  • 拓展:

对于门面模式可以举一个简单的例子,你去一家公司洽谈业务,你不需要了解这个公司内部是如何运作的,你甚至可以对这个公司一无所知,去的时候只需要找到公司入口处的前台美女,告诉她们你要做什么,她们会找到合适的人跟你接洽,前台的美女就是公司这个系统的门面。再复杂的系统都可以为用户提供一个简单的门面,Java Web开发中作为前端控制器的Servlet或Filter不就是一个门面吗,浏览器对服务器的运作方式一无所知,但是通过前端控制器就能够根据你的请求得到相应的服务。调停者模式也可以举一个简单的例子来说明,例如一台计算机,CPU、内存、硬盘、显卡、声卡各种设备需要相互配合才能很好的工作,但是如果这些东西都直接连接到一起,计算机的布线将异常复杂,在这种情况下,主板作为一个调停者的身份出现,它将各个设备连接在一起而不需要每个设备之间直接交换数据,这样就减小了系统的耦合度和复杂度。

如下图所示:

img

使用门面模式后:

img

迪米特法则用通俗的话来将就是不要和陌生人打交道,如果真的需要,找一个自己的朋友,让他替你和陌生人打交道。

2.请你解释一下,内存中的栈(stack)、堆(heap) 和静态区(static area) 的用法。

  • 堆:专门用来保存对象的实例(new 创建的对象和数组),实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中)

    • 1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)

    • 2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身.

    • 3.一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。

  • 栈:对象实例在堆中分配好以后,需要在Stack中保存一个4字节的堆内存地址,用来定位该对象实例在堆中的位置,便于找到该对象实例。

    • 1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中

    • 2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。

    • 3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

    • 4.由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.

  • 静态区/方法区:

    • 1.方法区又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

    • 2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

    • 3.全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。

3.请谈一谈,什么情况下会发生死锁?解决死锁的策略有哪些?

  • 死锁发生的四个必要条件是: 1.资源互斥使用。 即存在这样一种资源,它在某个时刻只能被分配给一个执行绪(也称为线程)使用; 2.多个进程保持一定的资源,但又请求新的资源。 3.资源不可被剥夺。即执行程序获得到的互斥资源不可被强行剥夺,换句话说,只有资源占用者自己才能释放资源; 4.多个进程循环等待。若干执行绪以不同的次序获取互斥资源,从而形成环形等待的局面,想象在由多个执行绪组成的环形链中,每个执行绪都在等待下一个执行绪释放它持有的资源。

  • 一般死锁的应对策略有: 1.死锁预防。如进程需要的所有资源,在一开始就全部申请好得到之后再开始执行。 2.死锁避免。如进程每次申请申请资源的时候,根据一定的算法,去看该请求可能不可能造成死锁,如果可能,就不给它分配该资源。 3.死锁处理。破坏四个必要条件的其中一个,比如kill掉一个进程。 4.死锁忽略。不管死锁,由用户自行处理,比如重启电脑。一般的系统其实都采取这种策略。

编程题:(来自力扣)

1.一年中的第几天 (将自己的分析思路写出)

给你一个按 YYYY-MM-DD 格式表示日期的字符串 date, 请你计算并返回该日期是当年的第几天。

思路:

  • 用字符串分割出月日

int YY= Integer.parseInt(date.split("-")[0]);
int MM = Integer.parseInt(date.split("-")[1]);
int DD = Integer.parseInt(date.split("-")[2]);
  • 利用数组储存每个月的前一个月有多少天

int []monthsDay = {0,31,28,31,30,31,30,31,31,30,31,30,31};
  • 利用月份进行循环

    • 当月份等于2时,执行闰年的判断

    • 判断之后,如果是闰年可以直接加一天,或者修改数组第2个元素的值为29。

  • for(int i=0;i<MM;i++){
           days += monthsDay[i];
           if (i==2&((YY%4==0&&YY%100!=0)||(YY%400==0))){
               days =days+1;  //或者用monthsDay[2]=29
           }
    }
  • 最后把当前之前每个月的累计和与分割出来的DD进行加法计算。

totalDays = days+DD;
System.out.println(date+"是今年的第"+totalDays+"天");

通常情况下,我们认为 1 月 1 日是每年的第 1 天, 1 月 2 日是每年的第 2 天,依此类推。每个月的天 数与现行公元纪年法(格里高利历)一致。

示例 1:

输入:date = "2019-01-09" 输出:9 示例 2:

输入:date = "2019-02-10" 输出:41 示例 3:

输入:date = "2003-03-01" 输出:60 示例 4:

输入:date = "2004-03-01" 输出:61

提示:date.length == 10 date[4] == date[7] == '-',其他的 date[i] 都是数字。 date 表示的范围从 1900 年 1 月 1 日至 2019 年 12 月 31 日。

完整程序

public class test {
    public static void main(String[] args) {
        String date = "2004-03-01";
        int YY= Integer.parseInt(date.split("-")[0]);
        int MM = Integer.parseInt(date.split("-")[1]);
        int DD = Integer.parseInt(date.split("-")[2]);
        int []monthsDay = {0,31,28,31,30,31,30,31,31,30,31,30,31};
        int days = 0;
        int totalDays = 0;
​
        for(int i=0;i<MM;i++){
               days += monthsDay[i];
               if (i==2&((YY%4==0&&YY%100!=0)||(YY%400==0))){
                   days =days+1;
               }
        }
        totalDays = days+DD;
        System.out.println(date+"是今年的第"+totalDays+"天");
    }
}

2.编写一个加密程序。

要求从键盘上输入一字符串(可含数字、大小写字母、特殊符号(空格 , . ?!) ),及一个密码K(密码取值为 1-99)。 加密规则是: 特殊符号(空格 ,. ?!)不加密,直接原样输出; 大小写字母在字母空间内向后循环移动 K位; 数字在数字空间中向后循环移动 K位。

思路:

  • 1.实际上是在空间内循环,所以先用ASCII码(也在空间内)减去空间第一个元素的值,所得的差值X相当于空间内第X个值

  • 2.用X加上密码值进行加密

  • 3.对加密后的值取余,余数Y相当于空间内第Y个值

  • 4.最后加上空间第一个元素的值,即可得到字母或数字的ASCII码值。

    • 字符转ASCII码值:在字符前面用(int)进行强转

    • ASCII码转字符:在数值前用(char)进行强转

实现:

import java.util.Scanner;
​
public class test2 {
    public static void main(String[] args) {
        System.out.println("请输入加密字符:");
        Scanner input = new Scanner(System.in);
        String encryption = input.nextLine();
        System.out.println("请输入密码(1-99):");
        int keyword = input.nextInt();
        char[] strArr1 = encryption.toCharArray();
        System.out.println("加密前的字符:"+encryption);
        for (int i = 0; i < strArr1.length; i++) {
            if (Character.isDigit(strArr1[i])){
                /*
                1.实际上是在空间内循环,所以先用ASCII码(也在空间内)减去空间第一个元素的值,所得的差值X相当于空间内第X个值
                2.用X加上密码值进行加密
                3.对加密后的值取余,余数Y相当于空间内第Y个值
                4.最后加上空间第一个元素的值,即可得到字母或数字的ASCII码值。
                 */
                strArr1[i] = (char)((((int)strArr1[i]-48+keyword)%10)+48);
            }
            else if (Character.isUpperCase(strArr1[i])){
                //如果是字母,则将其转化为ASCII码,然后再做运算,再转为char
                strArr1[i] = (char)((((int)strArr1[i]-65+keyword)%26)+65);
            }
            else if (Character.isLowerCase(strArr1[i])){
                //如果是字母,则将其转化为ASCII码,然后再做运算,再转为char
                strArr1[i] = (char)((((int)strArr1[i]-97+keyword)%26)+97);
            }
​
        }
        String str = String.valueOf(strArr1);
        System.out.print("加密后的字符为:"+str);
​
    }
}

3.在开发过程你用到过那些设计模式?用在什么场合?除单例模式外写出其他一种你常用的设计模式?

MVC设计模式:M-Model(模型,也叫DAO层):封装应用程序的状态;V-View(视图):表示用户界面;C-Controlle(bean层)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值