四川某商行笔试

面试:

先做三题,简单,但有一题做错,如下:

class Child {
    String s1 = new String("123");
    String s2 = "456";
    char s[] = {'a' , 'b' , 'c'};
    int a = 5;

public void change(String s1 , String s2 , char s[] , int a) {
        s1 = "112233";
        s2 = "445566";
        s[0] = 'A';
        a = 10;
}
public static void main(String[] args) {
        Child c = new Child();
        c.change(c.s1 , c.s2 , c.s , c.a);
        System.out.println(c.s1);
        System.out.println(c.s2);
        System.out.println(c.s);
        System.out.println(c.a);
}

应输出:

123 

456

Abc

5

=> s1和s2未发生改变(引用传递);s发生改变(引用传递);a未发生改变(值传递)

=> String类型是引用类型,按道理说引用传递,但为什么不发生改变?

=> String对象,值先放在常量池,对象放在堆,对象指向常量池的值。

=> String传到函数里赋新值,新值再次在常量池里创建,然后实参指向新的地址,但形参未发生指向的改变。因此Java归根结底是值传递!

(1)offer情况+为什么不去+实习公司薪资+转正薪资

(2)对数据库有了解吗,主键和外键,平时设计的时候会去设置吗?

(3)你会哪一块?擅长哪一块?对哪一方面最有热情,不惜一切去完成。

(4)SpringCloud和SpringBoot有什么区别?SpringCloud各个服务之间怎么通信?你的服务是有状态还是无状态的?我回答session,存放redis(有状态的);但是忘记说token(无状态)。

(5)对Python有了解吗?我回答否,但是会C/C++,从这个开始入门的。其实之前上课了解过一点。

(6)期望月薪多少?说实话,说低了....但该行平台很不错,想干一辈子,增长空间大。

(7)实习做的什么?你们实习公司产品的定位是什么,面向的用户是?整个系统的流程是怎么实现的,你有了解吗?我说到GRPC的时候,就被打断了。

(8)无反问环节。体验良好,但愿收到体检通知。


1.C++宏。

#define PI 3.14
标识符被宏定义后,则:标识符 == 宏名

程序中出现的是宏名;
在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换。

替换后才进行编译,宏替换是简单的替换。 
__LINE__  :当前程序行的行号,表示为十进制整型常量
__FILE__  :当前源文件名,表示字符串型常量
__DATE__ :转换的日历日期,表示为Mmm dd yyyy 形式的字符串常量,Mmm是由asctime产生的。
__TIME__  :转换的时间,表示"hh:mm:ss"形式的字符串型常量,是有asctime产生的。(asctime貌似是指的一个函数)

 ex:

#include<iostream>
#define LINE __LINE__
#define FILE __FILE__

#define TIME __TIME__
#define DATE __DATE__
using namespace std;
int main() { 
	cout<<LINE<<endl;
	cout<<FILE<<endl;
	cout<<TIME<<endl;
	cout<<DATE<<endl;
	return 0;
} 

2.数据库死锁特点。

产生死锁的四个必要条件:互斥;请求和保持;不可抢占;循环等待。

a. 使用乐观锁进行控制。乐观锁大多是基于数据版本(Version)记录机制实现。
即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表
增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。
此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,
如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
乐观锁机制避免了长事务中的数据库加锁开销(用户A和用户B操作过程中,都没有对数据库数据加锁),
大大提升了大并发量下的系统整体性能表现。Hibernate 在其数据访问引擎中内置了乐观锁实现。
需要注意的是,由于乐观锁机制是在我们的系统中实现,
来自外部系统的用户更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。

b. 使用悲观锁进行控制。悲观锁大多数情况下依靠数据库的锁机制实现,
如Oracle的Select … for update语句,以保证操作最大程度的独占性。
但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时
(如更改用户账户余额),如果采用悲观锁机制,也就意味着整个操作过程中
(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),
数据库记录始终处于加锁状态,可以想见,如果面对成百上千个并发,
这样的情况将导致灾难性的后果。所以,采用悲观锁进行控制时一定要考虑清楚。

  事务回退机制:略,后续有机会补充。

3.父子类,各有构造函数,各有普通函数,各有一个成员变量x,分别调用普通函数后的,x值的变化情况。

package com.example.kevintest.demo.msh;
public class Father {
    public Father() {
        System.out.println("father 构造函数");
    }
    public void  move() {
        System.out.println("father move");
    }
}
class Child extends Father {
    public Child() {
        System.out.println("child 构造函数");
    }
    public void  move() {
        System.out.println("child move");
    }
    public static void main(String[] args) {
        Father fc = new Child();
        fc.move();
        System.out.println("");
        Father f = new Father();
        f.move();
    }
}


console:
father 构造函数
child 构造函数
child move

father 构造函数
father move

4.Tomcat简述,怎么部署应用,常用开发工具?

5.JSP中上传数据到后台Servlet,用什么类对象接收的?用什么方法取出数据的?

request;

request.getParameter();

6.前中序遍历,求后序。

//层序遍历
void FloorPrint_QUEUE(pTreeNode &Tree) //层序遍历_队列实现
{
    queue < pTreeNode> q;
    if (Tree != NULL)
    {
        q.push(Tree);   //根节点进队列
    }

    while (q.empty() == false)  //队列不为空判断
    {
        cout << q.front()->data << " → "; 

        if (q.front()->leftPtr != NULL)   //如果有左孩子,leftChild入队列
        {
            q.push(q.front()->leftPtr);   
        }

        if (q.front()->rightPtr != NULL)   //如果有右孩子,rightChild入队列
        {
            q.push(q.front()->rightPtr);
        }
        q.pop();  //已经遍历过的节点出队列
    }
}

7.数据库索引采用的底层数据结构。

B+树。

索引的数据结构分为Hash和B+树。

Hash更适合单个值的查找,O(1);

B+树更适合范围查找,因为叶子节点形成了一个有序链表。

与B树的区别体现在:B+树中只有叶子节点才有value,非叶子节点只有key;B树所有节点都有key和value;

8.函数命名规范。

9.函数形参,包含指针和地址等情况的合法性。

10.SQL语句

11.Linux函数(10个左右)

消息队列的创建:

key_t ftok(char *pathname, char proj);

 创建进程:fork();

读文件:read();写文件:write;打开文件:open();

函数返回从TC1970-1-1 0:0:0开始到现在的秒数   :time_t time(time_t * timer)   

12.数据库类型

CREATE TABLE IF NOT EXISTS `runoob_tbl`(
   `runoob_id` INT UNSIGNED AUTO_INCREMENT,
   `runoob_title` VARCHAR(100) NOT NULL,
   `runoob_author` VARCHAR(40) NOT NULL,
   `submission_date` DATE,
   PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

13.创建数组的方法

14.冒泡排序最坏情况的时间复杂度

最坏的情况 => 对于 n 位的数列则有比较次数为 (n-1) + (n-2) + ... + 1 = n * (n - 1) / 2,这就得到了最大的比较次数。

15.C++指针类型的变量初始化。

16.doGet和doPost的区别?

等等。


(1)

Heap = 新生代(约1/3) + 老年代(约2/3);

新生代 = Eden(8/10)+ From Survivor(1/10) + To Survivor(1/10);8:1:1

新生代常用标记-复制算法;老年代常用标记-整理算法。

(2)多线程:

一、corePoolSize 线程池核心线程大小

线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,
他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。

二、maximumPoolSize 线程池最大线程数量

一个任务被提交到线程池以后,首先会找有没有空闲存活线程,
如果有则直接将任务交给这个空闲线程来执行,如果没有则会缓存到工作队列(后面会介绍)中,
如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,
而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,
它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。

三、keepAliveTime 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,
这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定

四、unit 空闲线程存活时间单位

keepAliveTime的计量单位

五、workQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。
jdk中提供了四种工作队列:

①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

④PriorityBlockingQueue

具有优先级的无界阻塞队列,优先级通过参数Comparator实现。

六、threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

七、handler 拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,
这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,
jdk中提供了4中拒绝策略:

(3)单例模式:

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

创建线程的三种方式:

1.继承Thread类

2.实现Runnable接口

3.实现Callable接口

1. sleep()方法:可以让正在运行的线程进入阻塞状态,直到休眠时间满了,进入就绪状态。
2. yield()方法:可以让正在运行的线程直接进入就绪状态,让出CPU的使用权。

sleep()是使线程暂停执行一段时间的方法。wait()也是一种使线程暂停执行的方法。例如,当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。并且可以调用notify()方法或者notifyAll()方法通知正在等待的其他线程。notify()方法仅唤醒一个线程(等待队列中的第一个线程)并允许他去获得锁。notifyAll()方法唤醒所有等待这个对象的线程并允许他们去竞争获得锁。具体区别如下:

1)  原理不同。sleep()方法是Thread类的静态方法,是线程用来控制自身流程的,他会使此线程暂停执行一段时间,而把执行机会让给其他线程,等到计时时间一到,此线程会自动苏醒。例如,当线程执行报时功能时,每一秒钟打印出一个时间,那么此时就需要在打印方法前面加一个sleep()方法,以便让自己每隔一秒执行一次,该过程如同闹钟一样。而wait()方法是object类的方法,用于线程间通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程调用notify()方法或者notifyAll()时才醒来,不过开发人员也可以给他指定一个时间,自动醒来。

2)  对锁的 处理机制不同。由于sleep()方法的主要作用是让线程暂停执行一段时间,时间一到则自动恢复,不涉及线程间的通信,因此,调用sleep()方法并不会释放锁。而wait()方法则不同,当调用wait()方法后,线程会释放掉他所占用的锁,从而使线程所在对象中的其他synchronized数据可以被其他线程使用。

3)  使用区域不同。wait()方法必须放在同步控制方法和同步代码块中使用,sleep()方法则可以放在任何地方使用。sleep()方法必须捕获异常,而wait()、notify()、notifyAll()不需要捕获异常。在sleep的过程中,有可能被其他对象调用他的interrupt(),产生InterruptedException。由于sleep不会释放锁标志,容易导致死锁问题的发生,因此一般情况下,推荐使用wait()方法。 

更多详见:https://blog.youkuaiyun.com/zenggeweiss/article/details/90342282

(4)

简单工厂模式;

单例模式;

组合模式;

需要着重看:代理模式、观察者模式 

源码地址: https://pan.quark.cn/s/a741d0e96f0e 在Android应用开发过程中,构建具有视觉吸引力的用户界面扮演着关键角色,卡片效果(CardView)作为一种常见的设计组件,经常被应用于信息展示或实现滑动浏览功能,例如在Google Play商店中应用推荐的部分。 提及的“一行代码实现ViewPager卡片效果”实际上是指通过简便的方法将CardView与ViewPager整合,从而构建一个可滑动切换的卡片式布局。 接下来我们将深入探讨如何达成这一功能,并拓展相关的Android UI设计及编程知识。 首先需要明确CardView和ViewPager这两个组件的功能。 CardView是Android支持库中的一个视图容器,它提供了一种便捷定制的“卡片”样式,能够包含阴影、圆角以及内容间距等效果,使得内容呈现为悬浮在屏幕表面的形式。 而ViewPager是一个支持左右滑动查看多个页面的控件,通常用于实现类似轮播图或Tab滑动切换的应用场景。 为了实现“一行代码实现ViewPager卡片效果”,首要步骤是确保项目已配置必要的依赖项。 在build.gradle文件中,应加入以下依赖声明:```groovydependencies { implementation androidx.recyclerview:recyclerview:1.2.1 implementation androidx.cardview:cardview:1.0.0}```随后,需要设计一个CardView的布局文件。 在res/layout目录下,创建一个XML布局文件,比如命名为`card_item.xml`,并定义CardView及其内部结构:```xml<and...
下载前可以先看下教程 https://pan.quark.cn/s/fe65075d5bfd 在电子技术领域,熟练运用一系列专业术语对于深入理解和有效应用相关技术具有决定性意义。 以下内容详细阐述了部分电子技术术语,这些术语覆盖了从基础电子元件到高级系统功能等多个层面,旨在为读者提供系统且全面的认知。 ### 执行器(Actuator)执行器是一种能够将电能、液压能或气压能等能量形式转化为机械运动或作用力的装置,主要用于操控物理过程。 在自动化与控制系统领域,执行器常被部署以执行精确动作,例如控制阀门的开闭、驱动电机的旋转等。 ### 放大器(Amplifier)放大器作为电子电路的核心组成部分,其根本功能是提升输入信号的幅度,使其具备驱动负载或满足后续电路运作的能力。 放大器的种类繁多,包括电压放大器和功率放大器等,它们在音频处理、通信系统、信号处理等多个领域得到广泛应用。 ### 衰减(Attenuation)衰减描述的是信号在传输过程中能量逐渐减弱的现象,通常由介质吸收、散射或辐射等因素引发。 在电信号传输、光纤通信以及无线通信领域,衰减是影响信号质量的关键因素之一,需要通过合理的设计和材料选择来最小化其影响。 ### 开线放大器(Antenna Amplifier)开线放大器特指用于增强天线接收信号强度的专用放大器,常见于无线电通信和电视广播行业。 它通常配置在接收设备的前端,旨在提升微弱信号的幅度,从而优化接收效果。 ### 建筑声学(Architectural Acoustics)建筑声学研究声音在建筑物内部的传播规律及其对人类听觉体验的影响。 该领域涉及声波的反射、吸收和透射等物理现象,致力于营造舒适且健康的听觉空间,适用于音乐厅、会议室、住宅等场所的设计需求。 ### 模拟控制...
先看效果: https://pan.quark.cn/s/463a29bca497 《基坑维护施工组织方案》是一项关键性资料,其中详细阐述了在开展建筑施工过程中,针对基坑实施安全防护的具体措施与操作流程。 基坑维护作为建筑工程中不可或缺的一部分,其成效直接关联到整个工程的安全性、施工进度以及周边环境可能产生的影响。 以下内容基于该压缩包文件的核心信息,对相关技术要点进行了系统性的阐释:1. **基坑工程概述**:基坑工程指的是在地面以下构建的临时性作业空间,主要用途是建造建筑物的基础部分。 当基坑挖掘完成之后,必须对周边土壤实施加固处理,以避免土体出现滑动或坍塌现象,从而保障施工的安全性。 2. **基坑分类**:根据地质状况、建筑规模以及施工方式的不同,基坑可以被划分为多种不同的类别,例如放坡式基坑、设置有支护结构的基坑(包括钢板桩、地下连续墙等类型)以及采用降水措施的基坑等。 3. **基坑规划**:在规划阶段,需要综合考量基坑的挖掘深度、地下水位状况、土壤特性以及邻近建筑物的距离等要素,从而制定出科学合理的支护结构计划。 此外,还需进行稳定性评估,以确保在施工期间基坑不会出现失稳问题。 4. **施工安排**:施工组织计划详细规定了基坑挖掘、支护结构部署、降水措施应用、监测与检测、应急响应等各个阶段的工作顺序、时间表以及人员安排,旨在保障施工过程的有序推进。 5. **支护构造**:基坑的支护通常包含挡土构造(例如土钉墙、锚杆、支撑梁)和防水构造(如防渗帷幕),其主要功能是防止土体向侧面移动,维持基坑的稳定状态。 6. **降水方法**:在地下水位较高的区域,基坑维护工作可能需要采用降水手段,例如采用井点降水技术或设置集水坑进行排水,目的是降低地下水位,防止基坑内部积水对...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值