面试官从这些方面考察你的Android开发水平!

news2024/12/24 9:16:23

View基础(25题)

  • 什么是View
  • View的位置参数
  • MotionEvent
  • ViewRoot
  • DecorView
  • MeasureSpec

View三大流程(28题)

  • measure过程
  • View
  • ViewGroup
  • layout过程
  • draw过程
  • 获取View的宽高
  • Activity启动到加载ViewRoot的流程

自定义View(26题)

  • 四种实现方法
  • 直接继承View
  • 自定义属性
  • 直接继承ViewGroup
  • 性能优化
  • 硬件加速

事件分发机制(22题)

  • 三个重要方法
  • dispatchTouchEvent
  • onInterceptTouchEvent
  • onTouchEvent
  • 事件传递规则与要点
  • 事件传递规则
  • Activity的事件分发
  • Window的事件分发
  • DecorView的事件分发
  • 根View的事件分发
  • ViewGroup的事件分发
  • View的事件分发和事件处理

滑动冲突(8题)

  • 滑动冲突的三种场景
  • 滑动冲突处理原则和解决办法
  • 外部拦截
  • 内部拦截

滑动(39题)

  • 滑动的7种实现方法
  • 弹性滑动
  • Scroller
  • 动画
  • 延时策略
  • 侧滑菜单
  • DraweLayout
  • SlidingPanelLayout
  • NavigationView
  • ViewDragHelper
  • ViewDragHelper.Callback
  • GestureDetector
  • OnGestureListener
  • OnDoubleTapListener
  • OnContextClickListener
  • SimpleOnGestureListener

辅助类

  • ViewConfiguration
  • VelocityTracker

如需完整版 Android面试锦集 请点击免费领取

在这里插入图片描述

部分答案展示:

View基础(25题)

1、简述View的绘制流程

  1. onMeasure-测量:从顶层View到子View递归调用measure()方法,measure()内部调用onMeasure(), 在onMeasure()中完成测量工作
  2. onLayout-布局:从顶层View到子View递归调用layout()方法,layout调用onLayout(),会根据测量返回的视图大小和布局参数将View放置到合适位置。
  3. onDraw-绘制: ViewRoot会创建Canvas,然后执行onDraw()进行绘制。

2、onDraw()的绘制顺序

  1. 绘制背景
  2. 绘制View内容
  3. 绘制子View
  4. 绘制滚动条

3、requestLayout()的作用

  1. 请求重新测量、布局
  2. View(requestLayout)->ViewGroup(requestLayout)->DecorView(requestLayout)->ViewRootImpl(requestLayout)。
  3. 最终会触发ViewRootImplperformTraversals(), 会触发onMeasure()onLayout(),不一定会触发onDraw()

4、requestLayout在什么情况下只会触发测量和布局,而不会触发绘制

如果没有改变控件的left\right\top\bottom就不会触发onDraw()

5、invalidate()的作用

  1. 请求重新绘制
  2. 会递归调用父View的invalidateChildInParent->ViewRootImplinvalidateChildInparent()
  3. 最终会执行ViewRootImplperformTraversals(), 不会会触发onMeasure()onLayout(),会触发onDraw()也可能不触发onDraw()

View三大流程(28题)

1、ViewRoot如何完成View的三大流程?

  1. ViewRoot的performTraversals()开始View的绘制流程,依次调用performMeasure()performLayout()performDraw()
  2. performMeasure()最终执行父容器的measure()方法,并依此执行所有子View的measure方法。
  3. performLayout()和performDraw()同理

2、View三大流程的作用?(3)

  1. measure决定了View的宽/高,测量后可以通过getMeasuredWidth/Height来获得View测量后的宽/高,除特殊情况外该值等于View最终的宽/高
  2. layout决定了View的顶点坐标以及实际View的宽/高:完成后可以通过getTop/Bottom/Left/Right获取顶点坐标,并通过getWidth/Height()获得View的最终宽/高
  3. draw决定了View的显示,最终将View显示出来

3、什么时候测量宽高不等于实际宽高?

MeasuredWidth/height != getWidth/Height()的场景:更改View的布局参数并进行重新布局后,就会导致测量宽高 != 实际宽高

measure过程

View

4、View的measure方法的特点?

  1. View的measure方法是final类型方法——表明该方法无法被重载
  2. View的measure方法会调用onMeasure方法,onMeasure会调用setMeasuredDimension方法设置View宽/高的测量值

5、View的onMeasure源码要点

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //1. setMeasuredDimension方法设置View宽/高的测量值
        setMeasuredDimension(
                //2. 第一个参数是获得的测量宽/高(通过getDefaultSize获取)
                getDefaultSize(getSuggestedMinimumWidth(),  //3. 获取的建议最小的宽/高
                                    widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(),
                                    heightMeasureSpec));
}
  1. setMeasuredDimension方法设置View宽/高的测量值(测量值通过getDefaultSize获取)
  2. getDefaultSize用于获取View的测量宽/高

自定义View(26题)

四种实现方法

1、自定义View实现方法的分类?

分类注意点1注意点2注意点3
1.继承View重写onDraw()—绘制和支持padding重写onMeasure()—解决wrap_content问题
2.继承ViewGroup重写onMesaure()—测量子元素,测量自身,并且需要处理子View的margin和自身的padding必须实现onLayout()—布局子元素,并且处理子View的margin和自身的padding属性实现自身的LayoutParams并且重写LayoutParmas相关的3个方法—让子View的Margin属性生效
3.继承特定的View(TextView等)扩展较容易实现不需要额外支持wrap_contentpadding
4.继承特定的ViewGroup(LinearLayout等)方法2能实现的效果方法4都能实现

2、自定义View的注意点?(5)

  1. View需要支持wrap_content、padding
  2. ViewGroup需要支持子View的margin和自身的padding
  3. 尽量不要在View中使用Handler,View已经有post系列方法
  4. View如果有线程或者动画,需要及时停止(onDetachedFromWindow会在View被remove时调用)——避免内存泄露
  5. View如果有滑动嵌套情形,需要处理好滑动冲突

直接继承View

3、直接继承自View的实现步骤和方法:

  1. 重写onDraw,在onDraw中处理padding
  2. 重写onMeasure,额外处理wrap_content的情况
  3. 设定自定义属性attrs(属性相关xml文件,以及在onDraw中进行处理)
class CustomViewByView(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int):
        View(context, attrs, defStyleAttr, defStyleRes){
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int):this(context, attrs, defStyleAttr, 0)
    constructor(context: Context, attrs: AttributeSet):this(context, attrs, 0, 0)
    constructor(context: Context): this(context, null, 0, 0)

    var mColor = Color.RED

    init {
        //3. 自定义attrs中属性的获取
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomViewByView)
        mColor = typedArray.getColor(R.styleable.CustomViewByView_circle_color, Color.RED)
        typedArray.recycle()
    }

    //1. 重写onDraw方法
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.color = mColor //属性attrs给定的颜色
        //2. 需要处理padding
        val width = width - paddingLeft - paddingRight
        val height = height - paddingTop - paddingBottom
        canvas.drawCircle(paddingLeft + width.toFloat() / 2, paddingTop + height.toFloat() / 2,
                Math.min(width, height).toFloat() / 2, paint)
    }

    //3. 特别处理wrap_content的情况,给定一个最小值
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSpecSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSpecMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSpecSize = MeasureSpec.getSize(heightMeasureSpec)
        when{
            // 为wrap_content的边均使用最小值mMinWidth/mMinHeight
            widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST -> {
                setMeasuredDimension(minimumWidth, minimumHeight)
            }
            widthSpecMode == MeasureSpec.AT_MOST -> {
                setMeasuredDimension(minimumWidth, heightSpecSize)
            }
            heightSpecMode == MeasureSpec.AT_MOST -> {
                setMeasuredDimension(widthSpecSize, minimumHeight)
            }
        }
    }
}

事件分发机制(22题)

1、事件分发

  1. 点击事件的对象就是MotionEvent,因此事件的分发,就是MotionEvent的分发过程,
  2. 点击事件有三个重要方法来完成:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent

三个重要方法

2、简述Android的事件分发机制

事件分发顺序:Activty->ViewGroup->View
主要方法:dispatchTouchEvent-分发事件onInterceptTouchEvent-当前View是否拦截该事件onTouchEvent-处理事件
1. 父View调用dispatchTouchEvent开启事件分发。
2. 父View调用onInterceptTouchEvent判断是否拦截该事件,一旦拦截后该事件的后续事件(如DOWN之后的MOVE和UP)都直接拦截,不会再进行判断。
3. 如果父View进行拦截,父View调用onTouchEvent进行处理。
4. 如果父View不进行拦截,会调用子ViewdispatchTouchEvent进行事件的层层分发。

dispatchTouchEvent

3、dispatchTouchEvent的作用

  1. 用于进行事件的分发
  2. 只要事件传给当前View,该方法一定会被调用
  3. 返回结果受到当前View的onTouchEvent和下级View的dispatchTouchEvent影响
  4. 表示是否消耗当前事件

4、ViewGroup事件分发伪代码:

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean consume = false;
    boolean intercepted = false;

    intercepted = onInterceptTouchEvent(ev);
    // 1、没有被拦截,分发给子View
    if(intercepted == false){
        consume = child.dispatchTouchEvent(ev);
    }
    // 2、事件被拦截因此自己进行处理 || 子View没有消耗该事件因此自己进行处理
    if(intercepted == true || consume == false){
        // 3、交给当前View进行处理(调用的是View的dispatchTouchEvent,该方法就是处理事件,等效于onTouchEvent)
        consume = super.dispacthTouchEvent(ev);
    }

    return consume;
}

super.dispacthTouchEvent(ev): 就是调用ViewGroup父类View的dispacthTouchEvent方法。该方法是直接对事件的处理。

5、View事件分发伪代码:

public boolean dispatchTouchEvent(MotionEvent event) {
    boolean result = false;
    // 1. 判断是否有OnTouchListener,返回true,则处理完成
    if (mOnTouchListener != null){
        result = mOnTouchListener.onTouch(this, event);
    }
    // 2. 事件没有被消耗。并且,如果有代理,会执行代理的onTouchEvent方法
    if (result == false && mTouchDelegate != null) {
        result = mTouchDelegate.onTouchEvent(event);
    }
    // 3. 事件没有被消耗。才会调用onTouchEvent
    if (result == false) {
        result = onTouchEvent(event);

        // 4. 接收到UP事件,就会执行OnClickListener的onClick方法
        if(MotionEvent.ACTION_UP == action && mOnClickListener != null){
            mOnClickListener.onClick(event);
        }
    }
    // 5. 返回事件处理的结果(是否消耗该事件)
    return result;
}
  1. mTouchDelegate和mOnClickListener本质都是在onTouchEvent中执行的,作为伪代码就忽视这些细节了。并不影响整个流程的层级。

6、View和ViewGroup在dispatchTouchEvent上的区别

  1. ViewGroup在dispatchTouchEvent()中会进行事件的分发。
  2. View在dispatchTouchEvent()中会对该事件进行处理。

onInterceptTouchEvent

滑动冲突(8题)

滑动冲突的三种场景

1、滑动冲突的三种场景

  1. 内层和外层滑动方向不一致:一个垂直,一个水平
  2. 内存和外层滑动方向一致:均垂直or水平
  3. 前两者层层嵌套

滑动冲突处理原则和解决办法

2、 滑动冲突处理原则

  1. 对于内外层滑动方向不同,只需要根据滑动方向来给相应控件拦截
  2. 对于内外层滑动方向相同,需要根据业务来进行事件拦截
  3. 前两者嵌套的情况,根据前两种原则层层处理即可。

3、 滑动冲突解决办法

  1. 外部拦截:在父容器进行拦截处理,需要重写父容器的onInterceptTouchEvent方法
  2. 内部拦截:父容器不拦截任何事件,事件都传递给子元素。子元素需要就处理,否则给父容器处理。需要配合requestDisallowInterceprtTouchEvent方法。

外部拦截

4、外部拦截法要点

  1. 父容器的onInterceptTouchEvent方法中处理
  2. ACTION_DOWN不拦截,一旦拦截会导致后续事件都直接交给父容器处理。
  3. ACTION_MOVE中根据情况进行拦截,拦截:return true,不拦截:return false(外部拦截核心)
  4. ACTION_UP不拦截,如果父控件拦截UP,会导致子元素接收不到UP进一步会让onClick方法无法触发。此外UP拦截也没什么用。

5、onClick方法生效的两个条件?

  1. View可以点击
  2. 接收到了DOWN和UP事件

6、外部拦截,自定义ScrollView

//Kotlin
class CustomScrollView(context: Context,
                       attrs: AttributeSet?,
                       defStyleAttr: Int,
                       defStyleRes: Int): ScrollView(context, attrs, defStyleAttr, defStyleRes) {

    constructor(context: Context) : this(context, null, 0, 0)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : this(context, attrs, defStyleAttr, 0)

    var lastX: Int = 0
    var lastY: Int = 0

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {

        val curX = ev.x.toInt()
        val curY = ev.y.toInt()

        when(ev.action){
            ACTION_DOWN -> {
                parent.requestDisallowInterceptTouchEvent(true)
            }
            ACTION_MOVE -> {
                //如果是水平滑动则交给父容器处理
                if(Math.abs(curX - lastX) > Math.abs(curY - lastY)){
                    parent.requestDisallowInterceptTouchEvent(false)
                }
            }
            ACTION_UP -> null
            else -> null
        }
        lastX = curX
        lastY = curY
        return super.dispatchTouchEvent(ev)
    }
}

滑动(39题)

滑动的7种实现方法

1、View滑动的7种方法:

  1. layout:对View进行重新布局定位。在onTouchEvent()方法中获得控件滑动前后的偏移。然后通过layout方法重新设置。
  2. offsetLeftAndRight和offsetTopAndBottom:系统提供上下/左右同时偏移的API。onTouchEvent()中调用
  3. LayoutParams: 更改自身布局参数
  4. scrollTo/scrollBy: 本质是移动View的内容,需要通过父容器的该方法来滑动当前View
  5. Scroller: 平滑滑动,通过重载computeScroll(),使用scrollTo/scrollBy完成滑动效果。
  6. 属性动画: 动画对View进行滑动
  7. ViewDragHelper: 谷歌提供的辅助类,用于完成各种拖拽效果。

2、Layout实现滑动

/*================================*
* onTouchEvent-进行偏移计算,之后调用layout
*================================*/
 public boolean onTouchEvent(MotionEvent event) {
     float curX = event.getX(); //手指实时位置的X
     float curY = event.getY(); //Y
     switch(event.getAction()){
        case MotionEvent.ACTION_MOVE:
           int offsetX = (int)(curX - downX); //X偏移
           int offsetY = (int)(curY - downY); //Y偏移
    /**=============================================
     * 变化后的距离=getLeft(当前控件距离父控件左边的距离)+偏移量——调用layout重新布局
     *============================================*/
           layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
           break;
        case MotionEvent.ACTION_DOWN:
           downX = curX; //按下时的坐标
           downY = curY;
           break;
     }
     return true;
 }

3、offsetLeftAndRight和offsetTopAndBottom实现滑动

/*================================*
* onTouchEvent-进行偏移计算,直接调用
*================================*/
 public boolean onTouchEvent(MotionEvent event) {
     float curX = event.getX(); //手指实时位置的X
     float curY = event.getY(); //Y
     switch(event.getAction()){
        case MotionEvent.ACTION_MOVE:
           int offsetX = (int)(curX - downX); //X偏移
           int offsetY = (int)(curY - downY); //Y偏移
     /**=============================================
      * 对left和right, top和bottom同时偏移
      *============================================*/
           offsetLeftAndRight(offsetX);
           offsetTopAndBottom(offsetY);
           break;
        case MotionEvent.ACTION_DOWN:
           downX = curX; //按下时的坐标
           downY = curY;
           break;
     }
     return true;
 }

4、LayoutParams实现滑动:

  1. 通过父控件设置View在父控件的位置,但需要指定父布局的类型,不好
  2. 用ViewGroup的MariginLayoutParams的方法去设置margin
//方法一:通过布局设置在父控件的位置。但是必须要有父控件, 而且要指定父布局的类型,不好的方法。
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

/**===============================================
 * 方法二:用ViewGroup的MarginLayoutParams的方法去设置marign
 * 优点:相比于上面方法, 就不需要知道父布局的类型。
 * 缺点:滑动到右侧控件会缩小
 *===============================================*/
ViewGroup.MarginLayoutParams mlayoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
mlayoutParams.leftMargin = getLeft() + offsetX;
mlayoutParams.topMargin = getTop() + offsetY;
setLayoutParams(mlayoutParams);

5、scrollTo\scrollBy实现滑动

  1. 都是View提供的方法。
  2. scrollTo-直接到新的x,y坐标处。
  3. scrollBy-基于当前位置的相对滑动。
  4. scrollBy-内部是调用scrollTo.
  5. scrollTo\scrollBy, 效果是移动View的内容,因此需要在View的父控件中调用。
// 1、移动到目标位置
((View)getParent()).scrollTo(dstX, dstY);
// 2、相对滑动:且scrollBy是父容器进行滑动,因此偏移量需要取负
((View)getParent()).scrollBy(-offsetX, -offsetY);

6、scrollTo/By内部的mScrollX和mScrollY的意义

  1. mScrollX的值,相当于手机屏幕相对于View左边缘向右移动的距离,手机屏幕向右移动时,mScrollX的值为正;手机屏幕向左移动(等价于View向右移动),mScrollX的值为负。
  2. mScrollY和X的情况相似,手机屏幕向下移动,mScrollY为+正值;手机屏幕向上移动,mScrollY为-负值。
  3. mScrollX/Y是根据第一次滑动前的位置来获得的,例如:第一次向左滑动200(等于手机屏幕向右滑动200),mScrollX = 200;第二次向右滑动50, mScrollX = 200 + (-50)= 150,而不是(-50)。

7、动画实现滑动的方法

  1. 可以通过传统动画或者属性动画的方式实现
  2. 传统动画需要通过设置fillAfter为true来保留动画后的状态(但是无法在动画后的位置进行点击操作,这方面还是属性动画好)
  3. 属性动画会保留动画后的状态,能够点击。

8、ViewDragHelper

  1. 通过ViewDragHelper去自定义ViewGroup让其子View具有滑动效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/500017.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++三大特性—继承“复杂的菱形继承及菱形虚拟继承”

C的一个大坑:菱形继承 希望这篇文章能让你理解什么是菱形继承,以及菱形继承的注意事项 单继承与多继承 单继承:一个子类只有一个直接父类时称这个继承关系为单继承 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承…

【半监督学习】Match系列.2

本文简单介绍半监督算法中的Match系列方法:CoMatch(ICCV2021),CRMatch(GCPR2021),Dash(ICML2021),UPS(ICLR2021),SimMatch…

ajax、fetch、axios三者的异同

同:都是发送网络请求 异: 1.ajax ajax是异步的javascript和xml,用于创建快速的动态网页的技术。(用js发送异步的网络请求) 特点:局部刷新页面,无需重载整个页面。 很多小伙伴会误以为ajax是…

2023年的深度学习入门指南(12) - PEFT与LoRA

2023年的深度学习入门指南(12) - PEFT与LoRA 大家都知道,大模型的训练需要海量的算力。其实,即使是只对大模型做微调训练,也是需要大量的计算资源的。 有没有用更少的计算资源来进行微调的方法呢?研究者研发出了几种被Hugging F…

fastCGI使用

1.http解释 在使用fastCGI之前需要先了解什么是http,以及静态请求和动态请求。 1.什么是http HTTP是超文本传输协议,它定义了客户端和服务器端之间文本传输的规范。HTTP通常运行在TCP之上,使用80端口。HTTP是一种简单的请求-响应协议&#x…

GUN C编译器拓展语法学习笔记(二)属性声明

一、属性声明 1、存储段:section 1.1 GNU C编译器扩展关键字:__attribute__ GNU C增加了一个__attribute__关键字用来声明一个函数、变量或类型的特殊属性。主要用途就是指导编译器在编译程序时进行特定方面的优化或代码检查。例如,我们可以…

C语言三子棋小游戏

哈喽,大家好,今天我们要利用之前所学习的C语言知识来写一个三子棋小游戏。 目录 1.游戏 2.函数部分 2.1.菜单 2.2.初始化棋盘 2.3.打印棋盘 2.4.玩家下棋 2.5.电脑下棋 2.6.判断输赢 2.7.判断棋盘是否已满 3.完整代码展示 1.游戏 今天我们写的…

未知时间信息下雷达运动目标的计算高效重聚焦与估计方法

论文背景 在雷达成像中,回波信号在接收到之前可能已经被多次反射或散射,这样会导致回波信号的时间和频率发生变化。其中,距离向维度上的变化称为距离单元迁移(range cell migration,RCM),频率向…

Spring笔记

文章目录 1、什么是Spring?2、如何创建Spring3、Spring简单的读和取操作1.直接在spring-config.xml里面放置对象2.通过配置扫描路径和添加注解的方式添加Bean对象3.为什么需要五个类注解4.从spring中简单读取 Bean对象5.Resource和Autowired的异同 1、什么是Spring&…

Transformer结构细节

一、结构 Transformer 从大的看由 编码器输入、编码器、解码器、解码器输入和解码器输出构成。 编码器中包含了词嵌入信息编码、位置编码、多头注意力、Add&Norm层以及一个全连接层; 解码器中比编码器多了掩码的多头注意力层。 二、模块 2.1 Input Embeddi…

canvas学习之华丽小球滚动电子时钟

教程来自 4-3 华丽的小球滚动效果 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>华丽小球滚动时钟…

【AVL树的模拟实现】

1 AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决…

人工智能基础部分14-蒙特卡洛方法在人工智能中的应用及其Python实现

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分14-蒙特卡洛方法在人工智能中的应用及其Python实现&#xff0c;在人工智能领域&#xff0c;蒙特卡洛方法&#xff08;Monte Carlo Method, MCM&#xff09;被广泛应用于各种问题的求解。本文首先将…

wvp-GB28181-pro录像功能开发环境搭建、配置、使用

开发环境、调试环境搭建 开发wvp平台搭建 离线安装脚本&#xff1a;https://gitcode.net/zenglg/ubuntu_wvp_online_install.git 下载离线安装脚本&#xff0c;完成wvp平台的部署 开发环境要求 操作系统&#xff1a;包管理工具是apt ky10桌面版uos桌面版deepin桌面版ubuntu桌面…

ArmDot.NET Crack

ArmDot.NET Crack ArmDot是一个.NET加密工具&#xff0c;用于保护使用.NET编写的程序。 企业需要保护他们的知识产权&#xff0c;包括他们的算法、产品和使用的资源的源代码。 然而&#xff0c;.NET编译器会生成一个通用的可访问代码。代码中嵌入的资源很容易访问&#xff0c;并…

RocketMQ不同的类型消息

目录 普通消息 可靠同步发送 可靠异步发送 单向发送 三种发送方式的对比 顺序消息 事物消息 两个概念 事务消息发送步骤 事务消息回查步骤 消息消费要注意的细节 RocketMQ支持两种消息模式: 普通消息 RocketMQ提供三种方式来发送普通消息&#xff1a;可靠同步发送、…

剑指Offer题集(力扣)

文章目录 剑指Offer题集&#xff08;[力扣题单](https://leetcode.cn/problemset/all/?listIdlcof&page1)&#xff09;[剑指 Offer 03. 数组中重复的数字](https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/)[剑指 Offer 04. 二维数组中的查找](https:…

SSM框架练习一(登录后关联数据表的业务模型)

需要实现的整体功能&#xff1a; 登录反馈信息列表展示查询反馈信息发表反馈 1.数据库设计 创建数据库 创建表结构及其约束 添加测试数据 工具&#xff1a;PHP、Navicat create table tab_user(id int primary key auto_increment,uname varchar(30) not null,pwd varc…

Weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271复现)

文章目录 前言影响版本环境搭建漏洞复现深度利用 前言 CVE-2017-10271漏洞产生的原因大致是Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其中使用了XMLDecoder来解析用户传入的XML数据&#xff0c;在解析的过程中出现反序列化漏洞&#xff0c;导致可执行任意…

从搬砖工到架构师,Java全栈学习路线总结

&#x1f307;文章目录 前言一、前置知识二、 Web前端基础示例&#xff1a;1.文本域2.密码字段 三、后端基础一. Java基础二. 数据库技术三. Web开发技术四. 框架技术五. 服务器部署 四、其他技术五、全栈开发六、综合实践七、学习教程一、前端开发二、后端开发三、数据库开发四…