- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
PB 应用程序就是由许多共同协作完成特定任务的窗口组成的集合.
窗口在应用程序的开发工作中占有很大的比重,是非常重要的一个 PB 对象 。
窗口类型 | 描述 |
---|---|
Main |
①可以覆盖其他窗口,也可以被其他窗口覆盖 ②可以最大、最小化,可以用鼠标改变其 大小 ③可以有边框,可以有菜单 ④常用于应用主操作窗口 |
Child |
①可以被其他窗口覆盖,也可以覆盖其他窗口 ②可以最大或最小化,也可以用鼠标改变 其大小,父窗口最小或最大化时, Child 类型的窗口也相应的被最大或最小化 ③可以 有边框,但不能有菜单 ④位置是相对于其父窗口而言,用鼠标拖放其位置不能超过其 父窗口的范围 ⑤常被其他窗口打开 |
Response |
①不能最大、最小化,没有边框,不能用鼠标改变其大小 ②在继续执行程序之前,必须 对这种类型的窗口做出响应 ③常用于显示非常重要的信息 |
Popup |
①可以最大或最小化,在对这种类型的窗口响应之前,可以操作其他窗口 ②不随父窗口 最大和最小化 ③可以拥有菜单、边框 ④常用于显示其他窗口的辅助信息 |
-- General 属性页属性 | --Scroll 属性页属性 |
---|---|
-- ToolBar 属性页属性 | --Other 属性页 |
属性 | 简介 |
---|---|
Title |
窗口的标题 |
Tag |
和窗口相关的一个文本属性,可以理解成窗口的注释 |
MenuName |
和窗口相连的菜单 |
Visibl |
窗口是否可见 |
Enabled |
确定窗口的功能是否可用 |
TitleBar |
确定窗口是否有标题栏 |
ControlMenu, MaxBox, MinBox |
三个属性确定在窗口的标题栏是否显示最大、最小化以及关闭按钮 |
ClientEdge |
是否显示用户工作区边框 |
PaletteWindow |
该属性只用于 Popup 类型的窗口,确定是否显示标题栏图标和最大、最小化按钮 |
ContextHelp |
只用在 Response 类型的窗口上。确定是否支持上下文帮助。如果支持就在窗口的右上角显示一个问号图标 |
RightToLeft |
确定由右到左显示 |
Center |
窗口居中显示,不管屏幕分辨率如何设置。该属性在 PB 7.0 中没有,新增 |
Resizable |
决定窗口在运行时是否可以改变其大小 |
Border |
决定窗口是否有边框 |
WindowType |
确定窗口的类型,可用取值的含义,从字面意思可以理解。该属性在窗口打开时起作用 |
BackColor |
设置窗口的背景颜色 |
MdiClientColor |
用来确定 MDI 用户区的颜色 |
Icon |
用来设置窗口标题栏的图标 |
属性 | 简介 |
---|---|
HscrollBar, VscrollBar |
是否需要显示水平或垂直滚动条 |
UnitsPerLine |
用户在垂直滚动条上每次单击移动的 PB单位数。默认为 0,表示每次 滚动窗口高度的 1/100 |
UnitsPerColumn |
用户在水平滚动条上每次单击向左或者向右移动的 PB单位数。默认为 0,表示每次滚动窗口宽度的 1/100 |
ColumnsPerPage |
表示每页显示的列数。默认为 0,表示显示 10 列 |
LinesPerPage |
表示每页显示的行数。默认为 0,表示显示 10 行 |
属性 | 简介 |
---|---|
ToolBarVisible |
工具条是否可见 |
ToolBarAlignment |
确定工具条在窗口上的初始位置。 有 5 个可用的枚举型取值: AlignAtBootom!(底部)、AlignAtLeft!(左)、 AlignAtRight!(右)、 AlignAtTop!(顶部)、 Floating!(浮动) |
ToolBarX, ToolBarY, ToolBa rHeight 和 ToolBarWidth |
用来设置当工具条浮动显示时工具条的起始位置及高宽。默认取值都是 0 |
用来设置窗口的真实坐标、宽高和鼠标的默认指针.
当屏幕分辨率是 800 × 600 时,全屏显示的窗口 X, Y, Width 和 Height 分别是 0, 0, 3658, 2407.
窗口可以看作是一个容器,所以在窗口上可以放各种控件,来完成用户与程序的交互 。
控件 | 说明 |
---|---|
Button |
用来执行特定的命令,接受用户的键盘或鼠标操作。 该控件的 Text 属性一般用来 向用户说明该按钮的功能。 典型事件是 Clicked |
Picture button |
和控件 Button 相同,只是在它的上面还可以显示图形,提供更漂亮友好的界面。 典型事件也是 Clicked |
Static text |
显示指示性或解释性信息,文字只能单行显示。 一般很少在该控件上编程 |
Singlelineedit |
单行编辑,一般用来接受用户比较少的文字输入。 典型事件是 Modified,通常在该 事件上判断用户的输入是否符合既定规则,如是否是数字等 |
Multilineedit |
多行编辑,用来接收用户比较多的文字输入。 典型事件也是 Modified,通常在该事 件上判断用户的输入是否符合既定规则 |
Check box |
复选框,用来界定用户的输入,一般输入信息作为其他命令执行时的选项。 当有多个复选框时,它们间的连接符习惯性认为是“ and”。 重要属性是 Checked,通常用来判断该控件是否选中 |
Radio box |
单选按钮,用来界定用户的输入只能是给定值中的一个。 它的输入信息通 常用来选择其他命令互斥的执行方式。 重要属性 是 Checked,true 表示选中 |
Dropdownlistbox |
以紧凑列表框的形式给用户显示信息,通常在该控件中进行单选。 经常和光标 ( cursor ) 配 合 使 用 , 显 示 从 数 据 库 中 提 取 的 数 据 。 典 型 事 件 是 SelectionChanged ,通常在该事件上读取当前用户的选择信息 |
Listbox |
列表框,是显示信息的,但其显示格式不如 Dropdownlistbox 紧凑,也通常和光 标(cursor)配合使用,显示从数据库中提取的数据。但是,该控件经常可以同时 选中多行。典型事件也是 SelectionChanged ,通常在该事件上读取当前用户的选 择信息 |
DataWindow |
是 PB中最重要的、也是 PB最具特色的一个控件。 可以 完成对数据库中的所有数据操作 |
Group box |
将功能类似的或在功能模块上关系紧密的部件放置在一起,界面美观,可以 给用户一个操作上的暗示。很少在该控件上编程 |
事件 | 事件说明 |
---|---|
open |
在窗口打开之后,显示之前发生。 调整窗口大小、设置窗口实例变量、初始化一些控件 |
close |
窗口被关闭时发生。触发该事件后,没有办法阻止窗口的关闭 |
closequery |
在开始关闭窗口时发生,该事件返回一个0或1的返回值 如果返回值为1,则窗口不关闭,close事件也不会产生 如果返回值为0,则窗口被关闭 |
resize |
当窗口大小发生变化时变化,窗口被打开时也触发此事件 |
key |
当用户在键盘上按下一个键且插入点不在编辑区域时发生 |
activate |
在窗口成为活动窗口之前、 Open 事件触发完后触发 ,此事件发生后,Tab 值最小的对象得到焦点,如果没有 排序号,则窗口本身获得焦点 |
deactivate |
窗口变为不活动时发生 |
clicked |
户单击窗口的空白区域时发生,此区域不能有任何的空间或数据窗口 |
doubleclicked |
用户双击窗口的空白区域时发生,此区域不能有任何的空间或数据窗口 |
dragleave |
当可拖放对象或控件,离开空白区时发生 |
dragleave |
当可拖放对象或控件,在窗口中被拖动时发生 |
hotlinkalarm |
在动态数据交换(DDE)服务器应用发送了新的(修改后)的数据,且客 户DDE应用程序已经接收到数据时发生 |
mousedown |
空白区,单击鼠标左击时发生。 此事件与click事件相同,flags的值总为1 |
mousemove |
鼠标在窗口中移动时发生 |
mouseup |
放开鼠标左键时发生 |
rbuttondown |
空白区,按下鼠标右键时发生 |
remoteexec |
当一个DDE客户应用程序发送了一条命令时发生 |
remotehotlinkstart |
当一个DDE客户应用程序要开始一个热连接(hotlink)时发生 |
remotehotlinkstop |
当一个DDE客户应用程序要结束一个热链接时发生 |
remoterequest |
当一个DDE客户应用程序请求数据时发生 |
remotesend |
当一个DDE客户应用程序已经发送了数据时产生 |
systemkey |
当插入点不在编辑框中且用户按下【alt】或【alt+其他组合键时发生】 |
timer |
调用timer函数,启动定时器、设定时间后发生 |
toolbarmoved |
当MDI窗口中的工具栏被移动时发生 |
① open事件 。
Cb_Save.Enabled=False //禁用“保存”按钮的功能
SetPointer(HourGlass!) //将鼠标形状置为沙漏形
Dw_1.SetTransObject(SQLCA) //为数据窗口设置事务对象
Dw_1.Retrieve() //检索数据
② 避免用户因疏忽退出窗口而丢掉在数据窗口中的修改数据 ,通常在 CloseQuery 事件中判 断某些工作是否完成,并显示一个提示窗口询问用户,根据用户的确认,返回一个值来决定 是否触发窗口的 Close 事件.
返回值为 1,表示取消关闭动作;返回值为 0,表示继续执行Close 事件 。
Int li_flag
//如果数据窗口中没有修改,则允许执行 Close,直接返回
If dw_1.ModifiedCount() <= 0 And dw_1.DeletedCount() <= 0 Then Return 0
//如果数据窗口有修改,询问用户是否保存
li_flag = MessageBox("提示","数据已经修改,是否保存? ",Question!,YesNoCancel!,1)
Choose Case flag_i //根据用户选择执行
Case 1 //用户选择要保存数据
If dw_1.Update() = 1 Then //如果修改数据成功
Commit; //提交
Return 0 //继续执行 Close 事件
Else //修改数据不成功
rollback; //回退事务
li_flag = MessageBox("提示","数据错误,是否继续关闭!",Question!,YesNoCancel!,2) //显示错误
If li_flag = 1 Then
Return 0 //允许关闭
Else
Return 1 //不允许关闭
End If
End If
Case 2 //用户选择不保存数据
Rollback; //回退事务
Return 0 //允许执行 Close 事件
Case 3 //用户选择取消
Return 1 //不允许关闭
End Choose //用户所有的选择情况处理完毕
③ 在窗口的 Resize 事件中编写脚本,当用户调整窗口大小时,根据用户调整的 比例对窗口上的控件大小进行调整。首先定义两个实例变量用来保存调整之前的窗口大小 。
//open事件中代码
ii_width = This.width
ii_height = This.height
//Resize事件中代码
Int li_index //循环变量
DragObject lobj_every //用来获取窗口上的控件
For li_index = 1 To UpperBound(this.control[]) //对窗口中的所有控件逐一处理
lobj_every = control[li_index] //保存当前控件
lobj_every.x = lw_obj.x * (newwidth / ii_width) //重新设置 x 坐标
lobj_every.width = lobj_every.width * (newwidth / ii_width) //重新设置宽度
lobj_every.y = lobj_every.y * (newheight / ii_height) //重新设置 y 坐标
lobj_every.height = lobj_every.height * (newheight / ii_height) //重新设置高度
Next
ii_width = newwidth //保存当前宽度
ii_height = newheight //保存当前高度
函数用来打开其他的窗口 。
① 语法 。
Open ( Windowvar)
② 参数 。
Windowvar
是一个 Window
类型的参数,是要打开的窗口名称 ③ 返回 。
④ 举个栗子 。
//打开主窗口
Open(w_main)
注:连续调用Open函数,窗口不会被打开两次,只是第二次调用时会再次触发窗口 Activate 事件。为了避免这种情况,可以将脚本修改如下 。
If Not IsValid(w_main) Then //如果窗口没有打开
Open(w_main) //则打开该窗口
Else //如果窗口已经打开
W_main.BringToTop = True //将该窗口显示在最顶层
End If
竟然open函数调用两次也不能打开两个窗口,那么问题来了,怎么才能打开多个窗口呢?代码如下 。
① 打开和 w_edit 完全相同的一个窗口 。
w_edit lws_edit //定义一个窗口变量
Open(lws_edit) //创建窗口实例
②通过数组,打开多个实例窗口 。
w_edit lws_edit[3]
Int li_index
For li_index =1 To 3
Open(lws_edit[li_index])
Next
函数的作用是关闭窗口,释放窗口及其上面的控件所占用的内存空间,窗口的 CloseQuery 事件和 Close 事件触发 。
① 语法 。
Close ( Windowname )
② 参数 。
Windowname
是要关闭的窗口名称,是一个 Window
类型的变量 函数可以打开一个小信息窗口,不仅可以以多种方式给用户显示提示信息,还可以将用户的选择信息返回 .
小信息窗口有标题、提示信息、图标、按钮等 4 个元素,可以通过不同的参数来决定显示哪些或者显示哪种样式.
① 简单模式 。
只能显示提示信息,并有一个确认按钮,不能让用户进行选择 。
MessageBox(title,text)
参数 。
举个栗子 。
MessageBox(“错误提示” ,“数据保存错误! ” )
② 复杂模式 。
语法 。
MessageBox ( title, text {, icon {, button {, default } } } )
参数 。
图标icon取值如下 。
按钮button取值如下 。
参数取值 | 显示样式 | 返回值 |
---|---|---|
OK! |
显示 【确定】 按钮,该取值为默认值 | 总返回 1 |
OKCancel! |
显示 【确定】 和 【取消】按钮 | 1-【确定】, 2-【取消】 |
YesNo! |
显示 【是】 和 【否】按钮 | 1-【是】, 2-【否】 |
YesNoCancel! |
显示 【是】、 【否】 和 【取消】 三个按钮 | 1-【是】, 2-【否】, 3-【取消】 |
RetryCancel! |
显示 【重试】 和 【取消】按钮 | 1-【重试】, 2-【取消】 |
AbortRetryIgnore! |
显示 【放弃】、 【重试】和 【忽略】三个按钮 | 1-【放弃】, 2-【重试】, 3-【忽略】 |
举个栗子 。
li_flag = MessageBox("提示","是否保存数据? ",Question!,YesNoCancel!,1)
Choose Case li_flag
Case 1 //用户选择 Yes,保存数据
. . . . . . //处理语句
Case 2 //用户选择 No,不保存
. . . . . . //处理语句
Case 3 //用户选择了 Cancel,不进行任何操作
. . . . . . //处理语句
End Choose
① 打开一个窗口,并传递一个字符串 。
string ls_str
ls_str = '个人公众号:XiezhrSpace'
openwithparm( 窗口名,ls_str)
② 接收字符串 。
string ls_str
ls_str = message.stringparm
① 打开一个窗口,并传递一个数值 。
openwithparm( 窗口名,1)
② 接收数值 。
long ll_row
ll_row = message.doubleparm
① 打开一个窗口,并传递一个结构体 。
st_parameter s_pm
s_pm.a = 1
openwithparm( 窗口名,s_pm)
② 接收结构体 。
st_parameter s_pm
s_pm = message.powerobjectparm
messagebox('提示',s_pm.a)
① 打开一个窗口,并传递一个用户对象 。
//(1)、创建类用户对象u_parameter,并定义实例变量
//(2)、给用户对象赋值,并传递该用户对象
u_parameter u_pm
u_pm.a = '1'
openwithparm(窗口名,u_pm)
② 接收用户对象 。
u_parameter u_pm
u_pm = message.powerobjectparm
messagebox('提示',u_pm.a)
① 打开一个exe,并传递参数 。
ls_exe = 'a.exe' + '|值1|' + '|值2|'
run(ls_exe)
② 接收exe传递的参数 。
string ls_parameter
ls_parameter = commandparm()
① 传递string消息 。
w_main.triggerevent('ue_open',0,'test')
//在用户自定义事件ue_open中接收消息:
string ls_msg
ls_msg = string(message.longparm,'address')
② 传递long消息 。
w_main.triggerevent('ue_open',100,0)
//在用户自定义事件ue_open中接收消息:
long ll_msg
ll_msg = message.wordparm
u_customvisual u_cv
u_cv = create u_customvisual
openuserobjectwithparm(u_cv,1)
① 语法 。
CloseWithReturn ( windowname, Returnvalue )
② 参数 。
windowname
是要关闭的窗口的名称 Returnvalue
要返回的数值 注:只有被关闭的窗口是 response 类型才能有效地获取返回参数 。
obj.triggerevent(clicked!)
obj.trigger event ue_init()
obj.trigger function wf_init()
obj.postevent(clicked!)
obj.post event ue_init()
obj.post function wf_init()
obj.dynamic event ue_init()
obj.dynamic function wf_init()
注:
动态调用和静态调用的区别
静态调用就是在编译代码时就对函数进行彻底编译
动态调用就是在程序执行的时候才回去查找和调用相应的函数
idle(60) //如果60秒没有操作的话就触发application对象的idle事件
timer(60) //每隔60秒就触发一次窗口的timer事件
① 创建窗口实例 。
w_edit lws_edit
Open(lws_edit)
② 打开多个窗口实例 。
w_edit lws_edit[3]
Int li_index
For li_index =1 To 3
Open(lws_edit[li_index])
Next
根据 tag 的取值对各个控件进行初始化 。
Int li_index,li_total
DataWindow ldw_temp
DropDownListbox lddlb_temp
RadioButton lrb_temp
li_total = Upperbound(Parent.Control[])
For li_index = 1 To li_total
Choose Case Lower(Parent.Control[li_index].Tag)
Case "DataWindow"
ldw_temp = Parent.Control[li_index]
ldw_temp.Reset()
Case "DropDownListbox"
lddlb_temp = Parent.Control[li_index]
lddlb_temp.SelectItem(0)
Case "radiobutton"
lrb_temp = Parent.Control[li_index]
lrb_temp.Checked = False
Case Else
…
End Choose
Next
当程序最小化时打开 timer(在 deactive 中加入 timer(1)语句),并在 timer 事件中编写 。
程序激活时关闭 Timer 事件(在 Active 事件中加入 timer(0)语句) 。
If This.Icon = "appico.ico" Then
This.Icon = "reverse.ico"
Else
This.Icon = "appico.ico"
End If
以闪烁文字显示重要信息可以吸引用户的注意力,避免这些重要信息被忽略。通过周期性修改 visible 属性,可以实现闪烁效果 。
在窗口中,假设放置一个静态文本 st_1,在窗口的 Open 事件中定义 Timer 事件的间隔:Timer(1) 。
Timer 事件 中代码如下 。
If Mod(Second(Now()),2) = 1 Then
st_1.visible = False
Else
st_1.Visible = True
End If
窗口的 Open 事件中经常编写脚本来进行初始处理工作,如果这些工作花费的时间比较长,在窗口显示之前用户就得等待很长的时间 。
这时,可以如下脚本优化 。
第一种方案
① open 事件中添加代码 。
PostEvent("ue_openpost")
② ue_openpost 事件中添加代码 。
SetPoInter(HourGlass!)
dw_1.SetTransObject(SQLCA)
dw_1.Retrieve()
SetPoInter(Arrow!)
第二种方案:
open 事件中添加如下代码 。
dw_1.SetRedraw(False)
TriggerEvent("ue_openpost")
Dw_1.SetRedraw(True)
在开发应用程序中,可能要用到不带标题栏的窗口,而带有标题栏的窗口可以通过拖放 标题栏来移动窗口,如何移动没有标题栏窗口呢?
在要拖放窗口的 MouseDown 事件中编写代码,代码如下 。
Send(handle(this),274,61458,0)
窗口的 Resize 事件中编写脚本,根据当前窗口的大小来设置是否显示滚动条 。
① 声明函数 。
Subroutine GetScrollRange(Uint hWindow,Int nScrollBarFlag,ref Int nMin,ref Int nMax) Library "user.exe"
Function Int GetScrollPos(Uint hWindow,Int nScrollBarFlag) Library "user.exe"
② 定义实例变量 。
Int ii_width,ii_height
③ open 事件中添加代码 。
ii_width = This.Width
ii_height = This.Height
④ Resize 事件中实现 。
Uint hwindow
Int nScrollPos,nMinPos,nMaxPos
If This.WindowState = Minimized! Then //如果正在进行最小化,则直接返回
Return
End If
HWindow = Handle(This) //获取当前窗口的句柄
//下面开始处理水平滚动条
If This.Width < i_Width Then //如果小于打开时的宽度
This.HscrollBar = True //则显示水平滚动条
Elseif This.HscrollBar Then //如果大于或等于打开时的宽度,并且已经有滚动条
NScrollPos = GetScrollPos(hwindow,0) //使用 API 函数获取当前滚动条位置
GetScrollRange(hwindow,0,nMinPos,nMaxPos) //使用 API 函数获取滚动范围
If nScrollPos > nMinPos Then //如果用户滚动了滚动条并且此时不需要显示滚动条
Post(hwindow,276,6,0) //则在水平方向调整窗口中的内容到原来的位置
End If
This.HscrollBar = False //取消滚动条特性
End If
//下面开始处理垂直滚动条
If This.Height < i_Height Then //如果小于打开时的高度
This.VscrollBar = True //则显示垂直滚动条
Elseif This.VscrollBar Then //如果大于或等于打开时的高度,并且已经有滚动条
NScrollPos = GetScrollPos(hWindow,1) //使用 API 函数获取当前滚动条位置
GetScrollRange(hwindow,1,nMinpos,nMaxPos) //使用 API 函数获取滚动范围
If nScrollPos > nMinPos Then //如果用户滚动了垂直滚动条且不需再显示
Post(hwindow,277,6,0) //则垂直调整窗口中的内容到原来的位置
End If
This.VscrollBar = False //取消滚动条特性
End If
实现窗口居中 。
//***************************************************************
//* 功能: 将窗口移到屏幕的中央
//* 参数 1: aw_window 要处理的窗口
//* 返回值: (none)
//* 调用举例: gf_window_center(w_pay_mode) //将窗口置于屏幕的中央
//***************************************************************
Environment le_env
Int li_ScreenHeight, li_ScreenWidth
Long ll_posx,ll_posy
GetEnvironment(le_env)
li_ScreenHeight = PixelsToUnits(le_env.ScreenHeight,YPixelsToUnits!)
li_screenwidth = PixelsToUnits(le_env.ScreenWidth,XPixelsToUnits!)
If aw_window.width > li_ScreenWidth Then //如果窗口超宽
ll_posx = 1
Else
ll_posx = (li_ScreenWidth - aw_window.Width) / 2
End If
If aw_window.height > li_ScreenHeight Then //如果窗口超高
ll_posy = 1
Else
ll_posy = (li_ScreenHeight - aw_window.Height) / 2
End If
aw_window.Move(ll_posx ,ll_posy)
以上就是本期内容的全部,希望对你有所帮助。我们下期再见 (●'◡'●) 。
最后此篇关于PB从入坑到放弃(五)窗口使用技巧的文章就讲到这里了,如果你想了解更多关于PB从入坑到放弃(五)窗口使用技巧的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
前言 每日站会(Daily Standup)是团队统一节奏的、在固定时间发生的、帮助团队内部快速同步进展的敏捷实践活动: 站会的目的是让团队能更好地对齐 Sprint 目标;
jdbcTemplate 中的queryForList,你真的懂吗? 你想象中的queryForList是不是应该长成下面这种模样? String sql = "select *
python是一门清晰简洁的语言,如果你对一些细节不了解的话,就会掉入到那些深不见底的“坑”里,下面,我就来总结一些python里常见的坑。 列表创建和引用 嵌套列表的创建 使用*号来创建一个
如今,在DevOps当中建立安全体系显得比以往任何时候都更加重要。《2021年企业DevOps技能提升报告》指出,56%的受访者表示DevSecOps已经成为自动化工具中的一大必备要素。然而,D
前言 相信看到这个题目,可能大家都觉得是一个老生常谈的月经topic了。一直以来其实把握一个“值传递”基本上就能理解各种情况了,不过最近遇到了更深一点的“小坑”,与大家分享一下。 首先还是从最简
前言 Go 中的for range组合可以和方便的实现对一个数组或切片进行遍历,但是在某些情况下使用for range时很可能就会被"坑",下面用一段代码来模拟下:
大家好,我是明哥。 在开始之前,先考你一个非常 Go 味的经典问题:如何判断一个 interface{} 的值是否为 nil ? 这也是面试有可能会被问到的一个问题,这个问题很 “迷”,平时
ava并发包有很大一部分内容都是关于并发容器的,因此学习和搞懂这部分的内容很有必要。 Java 1.5 之前提供的同步容器虽然也能保证线程安全,但是性能很差,而 Java 1.5 版本之后提供的并发
大家好,我是煎鱼。 前几天在读者交流群里看到一位小伙伴,针对 interface 的使用有了比较大的疑惑。 无独有偶,我也在网上看到有小伙伴在 Go 面试的时候被问到了:
我是一名优秀的程序员,十分优秀!