java学习 connect(1,2,3,4)

学习java断断续续加起来已经有快三十天的时间了,之前的博客按照时间顺序写的,今天对其进行一次整合,像期末复习一样将表面内容略去,详细介绍重点及难点。

框架

刚好之前做学习ppt汇报的时候做了几张图,这里展示一下。
基础学习
基础→深入探究
实战项目

基础

编程语法

java是一个以面向对象编程为目的而开发的语言,以C++为基础,摒弃了C++中许多繁琐的操作,并按照面向对象的思想在底层进行优化。
java的基础语法很容易掌握,唯一有点困惑的地方大概就是java的引用概念,这一点其实在了解了java的运行机制,也就是JVM后,也变得很容易理解了。

混淆点1:继承访问修饰符

访问修饰符:public、protected、private、默认的

公共的 可以随意访问
受保护的 不一定(相同包内可以)
私有的 不可以访问
默认的 不一定 只在包范围内等同于public

对于受保护的限制,用一个练习小程序实际测试后,得到:
子类内部使用,可以访问。
父类定义,子类为空:
子类创建于本包,父类也包含在本包中,可以访问
子类创建于本包,父类不包含在本包中,不可访问
子类创建于非本包,父类包含在本包,可以访问
子类创建于非本包,父类不包含在本包,不可访问
总结:父类protected,只跟父类是否跟子类处于同一包有关。子类创建时,protected被限定为子类定义包的范围。

父类定义,子类中使用public重写:
都访问为子类重写内容
总结:处于同包时,子类重写父类,处于不同类时编译器将直接找到子类的public定义。

父类定义,子类使用protected重写:
子类创建于本包,父类也包含在本包中,可以访问
子类创建于本包,父类不包含在本包中,可以访问
子类创建于非本包,父类包含在本包,不可访问
子类创建于非本包,父类不包含在本包,不可访问
总结:编译器首先在子类创建时,无法访问其他包内的子类protected定义,父类在本包内时定义被子类重写,父类不在本包内时接访问子类。

难点2:转型

向上转型(自动转型)
子类对象可自动转型为父类类型。
1:父类 转型子类对象 = new 子类名();
2:父类=子类;
这一块深入理解的话,需要考虑一个问题,为什么要子类转型为父类?从初学者的角度去看,是因为要面向对象,要减少编程工作量等等等等。
但是如果从设计者的角度去看的话,又会有一个问题,使用面向对象的思想来节约编程量,那么怎么设计编译器的运行方式才能让子类转型父类这一方法实际可用呢?
既然用了子类转型,那么转型后的数据一定有意义,也就是说转型后的父类数据一定会被访问到,不然我们直接delete这个子类就行了,还留着它干嘛?
既然子类已经转型为父类了,那么访问的时候,肯定是跟访问父类的时候一样,按照父类的方法和属性去访问。
那么设计者设计自动转型的时候,如果子类需要转型回来,那么就是暂时隐藏子类的方法和属性。如果子类不需要转型回来,那么直接裁剪子类的方法和属性。很显然java采用的是前者。(因为程序和属性都是以存储在内存中的,每个类都拥有一个定位这些内容的地址表,只需要修改隐藏或裁剪这个地址表就可以了)

向下转型
即父类再重新转回为子类,之前子类自动转型时,是会暂时隐藏子类特有的方法和属性,而转回时这些内容又重新见了。
当然还存在一些之前没有子类实例向上转型,而直接从父类转型到子类的功能。说实话,我觉得java的设计者压根就没想让人们这么用,估计也就只有一些面试官会问到。

(尽量少使用向上转型,或总是跟向下转型成对出现)

混淆点3:构造方法

子类跟父类构造方法:
构造方法顺序:
无参数(同C++一样,先进行父类构造方法,再进行子类方法)
父类→子类
//隐式的自动调用父类方法

父类有参数
需要定义在子类构造方法内第一句加上super(*)来调用父类方法。
父类无参数
编译器自动在子类构造方法第一句加上了super(),也可以自己手动加上。

混淆点4:接口

接口的定义:
1、属性全是默认为静态常量
2、只能写抽象方法。但是用来实现接口的类跟类是一样的
继承extends: 单继承 一个类只能继承一个类
接口implements: 多实现,一个类可以实现多个接口
接口与抽象类的区别:
接口和抽象类都需要被别的类继承,自己无法创建实例化对象。但一个类可以继承多个接口,却只能继承一个抽象类。抽象类只有方法是抽象的,没有抽象属性一说,而接口中的属性是static final的,相当于定义了一个立即数(即int i=10;中的10)。

界面开发

界面开发基础工具:
1、java.awt 早期的界面开发包 保留使用元素类型
2、javax.swing 升级之后的开发包 主要升级了视图部分

知识点1:基本工具

常用界面:
JFrame 最基础的界面类(用来盛放其他组件)
FlowLayout 流式布局
JLabel 标签组件
JTextField 文本框
JButton 按钮
JCheckBox 点选框
Jpanel 平台(用来盛放其他组件)
JScrollPane 自动滚动框平台
JMenuBar、JMenu、JMenuItem 菜单栏相关组件

监听器:
动作监听器 :ActionListener(是一个接口,重要方法getActionCommand)
鼠标监听器:MouseListener (跟事件监听器类似,重要方法get坐标)

事件类:
动作事件类: ActionEvent
事件发生时,会将组件以及事件的信息打包传入监听响应方法中。
查阅java文档,新建监听类,打印event内信息,即可大致了解jframe的事件大概包括些什么。
鼠标事件类:MouseEvent
类似于ActionEvent,只是内部的属性会有一些区别。

绘图:
Graphics 类
这是一个特殊的类,它被定义为抽象类。所以在定义的时候是无法new的。
获取方式:
从可视化组件上获取,在可视化之后获取。
首先我们思考一个问题,既然graphics是用来绘图的,那么绘图需要知道哪些要素?
像素坐标,像素值。
知道了这些信息,就可以挨个像素给显示设备发送数据,让显示设备刷新缓存。到了这里就明白了为什么graphics没办法在一开始就创建对象了,因为一开始就创建的对象没有意义。我们不知道像素的坐标该如何求得,因为java界面是一个程序,它不可能一直把整个屏幕都占据住,我们只能在自己规定好的区域内绘制图案。所以graphics需要附着在某些可视化组件上,从而获取像素坐标的相对零点。
即g = 组件.getGraphics();
然后像素值就可以使用一些基本的方法自动求得,比如:
g.setColor(color);
g.drawLine(x1,y1,x2,y2);
g.fillRect
g.drawImage
等等

重点1:监听器实现

1、用自己的类实现监听器接口:
在按钮监听类内,进行判断函数,并执行动作。然而执行动作时需要访问界面类p的属性,界面类被定义在main函数中,无法访问。
解决办法:在监听类内定义界面类,在界面类内将this引用传入监听类,即可完成访问。
2、将监听器类与需要监听的组件关联
自己的Listener loginl = new 自己的Listener();
组件.addActionListener(loginl);

重点2:重绘

了解重绘之前,首先要了解一下显示器的运作。先说一个最简单的12864模块,这是一块128*64的单色液晶显示器,它是如何显示内容的呢?
不断扫描。
就跟我们高中学到的电子管显示器一样,任何一个显示器都是逐点扫描的。12864模块中液晶屏幕接受到的数据其实包含了行和列,然后该坐标处的像素被点亮。至于像素的亮度(即像素值),可以改变电流大小,也可以改变电流通过的频率,不同设备使用不一样的方法。
但是很显然我们的cpu不可能一直来控制液晶屏幕哪个点需要被点亮,所以这时候需要显示驱动和硬件电路来配合。比如12864中可以缓存一部分cpu送来的数据,然后硬件电路自行帮我们解析数据,然后再给液晶屏发送电流。
至于个人PC的显示设备如何驱动,我不太了解,估计也是由程序给显示驱动发送数据,数据可能包括像素点,像素值,这些数据用来覆盖显示器缓存中的原始数据。
也就是说只要我们不发送新数据,显示器上的点不会改变。实际创建一个界面,使用graphics绘制之后,拖动界面边框,发现出现黑边,或者原有图像不见了,也确实印证了我们的想法。
那么如何实现重绘呢?根据观察,jframe自身的组件可以实现重绘,它会不断调用自身的paint函数来实现重绘。而我们如果想让我们自己绘制的图案也得到重绘的话,需要在paint中加入自己的重绘函数,(要加上super.paint从而绘制出界面中的基础组件)。
而重绘图案的话需要知道已绘制图案的信息,这里有很多方法,可以记录每个基础图形的信息,可以记录绘制动作的等等。

知识点3:山脉绘制(递归)

初学者总是认为递归很厉害,但是实际上递归真的是一种对程序员也不友好对计算机也不友好的实现方式。
首先考虑循环和递归的效率区别:
递归节省了少量的代码空间。
循环节省了大量的程序上下文空间。
在计算机中代码空间,一条指令基本上也就是32或64位这个样子,而程序上下文…至少传参要存储,程序指针要存储,临时变量要存储…
说正经的,递归其实就是用函数实现了循环和多重判断。
山脉递归就是不断取两侧中点,当发现间隔过小时返回。

知识点4:五子棋(博弈)

程序核心思想:
五子棋一共分为15*15个栅格,面向对象的思路是将每个落点设定为一个类的对象,该类名为Spot,包含X,Y,棋子颜色等属性。
比较简单的思路是创建一个列表,储存所有已经落下的棋子。
不过因为五子棋栅格一共只有225个,可以使用固定一位I维数组,这样相比于列表和二维数组来说加快了运行速度。
考虑胜负判断,我一开始写的递归,但是后来发现因为需要双向计算,所以递归其实并不方便(要调用8次函数!)。
后来老老实实使用了多重if嵌套,刚好这一套方法扩充以后就可以计算AI的权值了。
权重算法,落子后对每一个可能影响到的点重新计算权值,每次AI都会选择综合权值最大的一处栅格落子。
有了权重以后,就可以实现AI的单步对棋了。
要想实现多步推理,首先考虑一个旗手永远不肯能完成多步博弈,所以在推理时,必然会创建一个虚拟的对手,并令虚拟对手也使用某种推理方法进行落子。
然后考虑,每一种落子方式都将产生一个新的棋局,所以最终存储的棋局数是乘方增长的。
然后考虑,当我们得到所的棋局以后,该如何把未来的信息传递到当前呢?可以考虑用胜负情况传递回布尔收益来,也可以用将权值相加返回。但是由于越往后的步数局数越多,权值相加也越大,所以需要乘上一个衰减系数。
这是我的实现方式。但是效率很低,因为当推理步数多了以后,需要存储的棋局数太多了。
之后查阅资料发现,棋类博弈,一般使用剪枝算

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值