首页 文章 精选 留言 我的

精选列表

搜索[socket编程],共10000篇文章
优秀的个人博客,低调大师

python函数式编程之迭代器

什么是迭代器 顾名思义,就是更新换代的意思 python中的迭代器就是根据上一个结果生成下一个结果,一直循环往复不断重复的过程 迭代器有两个特点: 1.不断重复同一个过程 2.根据上一个结果生成下一个结果 迭代器的定义 先来看两个例子 代码一: while True: cmd = input("input your command: ").strip() print(cmd) 代码二: l1 = ["a", "b", "c", "d"] count = 0 while count < len(l1): print(l1[count]) count += 1 在代码一中,让用户不断输入命令,然后打印用户输入的命令,这是一个不断重复的过程,但是后一个结果跟前一个结果没有什么联系,所以代码一不是迭代器 在代码二中,先定义一个列表l1和count,在count的值小于列表l1的长度中,打印列表中count索引的值,然后count的值加1,这几行代码符合迭代器的定义 代码二的执行过程: 首先,打印列表l1中count索引的值,这是一个不断重复的过程 然后,每循环一次,count的值就在以前的基础上增加1,直到count的值等于列表l1的长度时,循环中止 所以代码一不是迭代器,代码二才是符后迭代器的定义标准 迭代器的作用 python中常见的数据类型包括字符串,列表,元组,字典,集合,文件 我们知道,python中的数据类型又分为有序和无序 对于有序数据类型,可以如上面的代码二所示,使用索引遍历有序数据类型中的元素 而对于无序数据类型,就不可以使用索引来遍历其中的元素了,此时可以使用for循环来遍历其中的元素 现在来看看for循环到底做了哪些事,可以取出无序数据类型中的元素 dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, } for k in dic1: print(k) 执行上面的程序,可以打印出字典dic1中所有的键 实际上,python为了提供一种不依赖于索引的迭代方式,python会为一些对象内置__iter__方法 在python中,如果一个对象有__iter__方法,那么这个对象就是可迭代对象 执行obj.__iter__()方法得到的结果就是迭代器 所以python中的迭代器,都会有__iter__方法和__next__方法 以上面定义的dic1为例 dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, } i = dic1.__iter__() # dic1.__iter__方法执行结果得到一个迭代器i print(i) # 打印迭代器,得到结果:<dict_keyiterator object at 0x0000000002DBD278> print(i.__next__()) # 执行迭代器i中的__next__方法,得到dic1中的一个元素,然后打印迭代出的元素 print(i.__next__()) # 再次执行迭代器的__next__方法,得到dic1的第二个元素,然后打印出来 print(i.__next__()) # 第三次执行迭代器的__next__方法,得到dic1的第三个元素,然后打印出来 由于python的字典是无序的数据类型,所以每次得到的dic1中的元素可能是不相同的 执行三次__next__方法,得到的结果如下 a b c 上面dic1的长度为4,如果执行5次__next__方法,会出错什么结果 dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, } i = dic1.__iter__() print(i.__next__()) print(i.__next__()) print(i.__next__()) print(i.__next__()) print(i.__next__()) 程序执行结果 a File "D:\python3\lib\unittest\loader.py", line 153, in loadTestsFromName b module = __import__(module_name) c File "E:\python_learn\py_code\test.py", line 21, in <module> d print(i.__next__()) StopIteration 可以看到,python解释器在执行第五次__next__方法时,抛出了StopIteration的错误,这说明如果执行__next__方法的次数超出迭代器的长度时,python解释会抛出异常 迭代器的优缺点 迭代器的优点 1.提供一种不依赖于索引的取值方式 2.提供惰性计算,每执行一次__next__方法,只会从迭代器中取出一个值,不管这个数据长度有多大,使用迭代器取值时,每取出一个值,占用的内存空间都一个元素的大小,非常节省内存空间 迭代器的缺点 1.取值比较麻烦。如果想用迭代器的方式取出列表中的第三个值,必须调用三次__next__方法,才能取出第三个值,而前两次取出的值实际上是没有作用的 2.一次性的,只能向后迭代,不能回退。如果运行两次__next__方法后,就不可能回退再去了迭代器的第一个值 3.不能获取到迭代器的长度,只能不停执行__next__方法,直到出现StopIteration的提示,此时才能知道迭代器的长度 for循环的执行过程 定义一个列表,使用for循环遍历取出列表中的值 l1 = ['a', 'b', 'c', 'd'] for i in l1: print(i) 在for循环的执行过程中,实际上for循环是把in后面的对象执行__iter__方法,得到一个迭代器对象,然后不停执行迭代器对象中的__next__方法,得到元素,然后把迭代出来的元素赋值给i,再调用print方法打印元素i,直到for循环捕捉到StopIteration异常,结束循环,程序停止 类似于下面的代码 l1 = ['a', 'b', 'c', 'd'] obj = l1.__iter__() while True: try: i = obj.__next__() print(i) except StopIteration: break 判断一个对象是迭代器对象还是可迭代对象 只要一个对象有__iter__方法,这个对象就是可迭代对象 一个可迭代对象有__next__方法,这个对象就是迭代器对象 判断python中的字符串,列表,元组,字典和文件对象是否是可迭代对象和迭代器对象 示例代码 from collections import Iterable, Iterator s1 = "hello" l1 = ['a', 'b', 'c', 'd'] t1 = ('a', 'b', 'c', 'd') set1 = {'a', 'b', 'c', 'd'} dic1 = {"a": 1, "b": 2, "c": 3, "d": 4, } f1 = open("db.txt", "w", encoding="utf-8") print(isinstance(s1, Iterable)) print(isinstance(l1, Iterable)) print(isinstance(t1, Iterable)) print(isinstance(set1, Iterable)) print(isinstance(dic1, Iterable)) print(isinstance(f1, Iterable)) print("*" * 30) print(isinstance(s1, Iterator)) print(isinstance(l1, Iterator)) print(isinstance(t1, Iterator)) print(isinstance(set1, Iterator)) print(isinstance(dic1, Iterator)) print(isinstance(f1, Iterator)) 执行结果: True True True True True True ****************************** False False False False False True 从上面的例子,可以看出,字符串,列表,元组,集合,字典和文件都是可迭代对象,其中只有文件是迭代器对象 在上面,我们知道,使用for遍历对象中的值时,是把in后面的对象的变为可迭代对象,然后调用__next__方法取出对象中的元素 既然文件本身就是迭代器对象,那使用for循环获取文件的内容时,又是怎么做的呢 先打开一个文件,打印出这个文件对象,再调用文件对象的__iter__方法得到迭代器对象,判断两个对象是否是同一个对象 f1 = open("db.txt", encoding="utf-8") print(f1) obj = f1.__iter__() print(obj) print(obj is f1) 执行结果 <_io.TextIOWrapper name='db.txt' mode='r' encoding='utf-8'> <_io.TextIOWrapper name='db.txt' mode='r' encoding='utf-8'> True 得到结论: 如果一个对象可以被for循环迭代,则这个对象一定是可迭代对象 文件对象被执行__iter__方法,得到的结果仍然是一个迭代器对象

优秀的个人博客,低调大师

《Java并发程编程艺术》重点总结

synchronized修饰的代码块同步执行,不在synchronized块中的代码会异步执行,因此推荐用同步代码块,而非同步整个方法。 synchronized修饰同步方法和代码块,一定是排队运行的(线程独占)。 多线程访问“共享变量”,才需要加同步。 同步不能继承。 当一个线程执行的代码出现异常,其持有的锁会自动释放。 synchronized加到static方法上是给Class类上锁。 synchronized加到实例方法上,是给对象上锁。 String常量池缓存,synchronized代码块加锁一般不使用String。 synchronized代码块具有volatile同步变量到主内存的功能。 wait()和notify()都是在同步方法、代码块中使用。 执行notify()后不会立即释放对象锁,等执行完synchronized代码块才释放,然后其他wait状态的线程才可以获得该对象锁。 线程间通信,可使用管道字节流、管道字符流;建立通信的管道两端,都是阻塞的,即写端无写入时,读端将会阻塞。类似于 Linux进程通信的pipe。 PipeInputStream/PipeOutputStream PipeReader/PipeWriter ReentrantReadWriteLock 具有读和写两个锁;读读共享锁、写写排他锁、读写排他锁(有写 就互斥)。

优秀的个人博客,低调大师

面向对象高级编程:定制类

看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。 __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数。 除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类。 __str__ 我们先定义一个Student类,打印一个实例: >>> class Student(object): ... def __init__(self, name): ... self.name = name ... >>> print(Student('Michael')) <__main__.Student object at 0x109afb190> 打印出一堆<__main__.Student object at 0x109afb190>,不好看。 怎么才能打印得好看呢?只需要定义好__str__()方法,返回一个好看的字符串就可以了: >>> class Student(object): ... def __init__(self, name): ... self.name = name ... def __str__(self): ... return 'Student object (name: %s)' % self.name ... >>> print(Student('Michael')) Student object (name: Michael) 这样打印出来的实例,不但好看,而且容易看出实例内部重要的数据。 但是细心的朋友会发现直接敲变量不用print,打印出来的实例还是不好看: >>> s = Student('Michael') >>> s <__main__.Student object at 0x109afb310> 这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。 解决办法是再定义一个__repr__()。但是通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法: class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name=%s)' % self.name __repr__ = __str__ __iter__ 如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。 我们以斐波那契数列为例,写一个Fib类,可以作用于for循环: class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def __next__(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration() return self.a # 返回下一个值 现在,试试把Fib实例作用于for循环: >>> for n in Fib(): ... print(n) ... 1 1 2 3 5 ... 46368 75025 __getitem__ Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素: >>> Fib()[5] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'Fib' object does not support indexing 要表现得像list那样按照下标取出元素,需要实现__getitem__()方法: class Fib(object): def __getitem__(self, n): a, b = 1, 1 for x in range(n): a, b = b, a + b return a 现在,就可以按下标访问数列的任意一项了: >>> f = Fib() >>> f[0] 1 >>> f[1] 1 >>> f[2] 2 >>> f[3] 3 >>> f[10] 89 >>> f[100] 573147844013817084101 但是list有个神奇的切片方法: >>> list(range(100))[5:10] [5, 6, 7, 8, 9] 对于Fib却报错。原因是__getitem__()传入的参数可能是一个int,也可能是一个切片对象slice,所以要做判断: class Fib(object): def __getitem__(self, n): if isinstance(n, int): # n是索引 a, b = 1, 1 for x in range(n): a, b = b, a + b return a if isinstance(n, slice): # n是切片 start = n.start stop = n.stop if start is None: start = 0 a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L 现在试试Fib的切片: >>> f = Fib() >>> f[0:5] [1, 1, 2, 3, 5] >>> f[:10] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 但是没有对step参数作处理: >>> f[:10:2] [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] 也没有对负数作处理,所以,要正确实现一个__getitem__()还是有很多工作要做的。 此外,如果把对象看成dict,__getitem__()的参数也可能是一个可以作key的object,例如str。 与之对应的是__setitem__()方法,把对象视作list或dict来对集合赋值。最后,还有一个__delitem__()方法,用于删除某个元素。 总之,通过上面的方法,我们自己定义的类表现得和Python自带的list、tuple、dict没什么区别,这完全归功于动态语言的“鸭子类型”,不需要强制继承某个接口。 __getattr__ 正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。比如定义Student类: class Student(object): def __init__(self): self.name = 'Michael' 调用name属性,没问题,但是,调用不存在的score属性,就有问题了: >>> s = Student() >>> print(s.name) Michael >>> print(s.score) Traceback (most recent call last): ... AttributeError: 'Student' object has no attribute 'score' 错误信息很清楚地告诉我们,没有找到score这个attribute。 要避免这个错误,除了可以加上一个score属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。修改如下: class Student(object): def __init__(self): self.name = 'Michael' def __getattr__(self, attr): if attr=='score': return 99 当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值: >>> s = Student() >>> s.name 'Michael' >>> s.score 99 返回函数也是完全可以的: class Student(object): def __getattr__(self, attr): if attr=='age': return lambda: 25 只是调用方式要变为: >>> s.age() 25 注意,只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。 此外,注意到任意调用如s.abc都会返回None,这是因为我们定义的__getattr__默认返回就是None。要让class只响应特定的几个属性,我们就要按照约定,抛出AttributeError的错误: class Student(object): def __getattr__(self, attr): if attr=='age': return lambda: 25 raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr) 这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。 这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。 举个例子: 现在很多网站都搞REST API,比如新浪微博、豆瓣啥的,调用API的URL类似: http://api.server/user/friends http://api.server/user/timeline/list 如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且,API一旦改动,SDK也要改。 利用完全动态的__getattr__,我们可以写出一个链式调用: class Chain(object): def __init__(self, path=''): self._path = path def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) def __str__(self): return self._path __repr__ = __str__ 试试: >>> Chain().status.user.timeline.list '/status/user/timeline/list' 这样,无论API怎么变,SDK都可以根据URL实现完全动态的调用,而且,不随API的增加而改变! 还有些REST API会把参数放到URL中,比如GitHub的API: GET /users/:user/repos 调用时,需要把:user替换为实际用户名。如果我们能写出这样的链式调用: Chain().users('michael').repos 就可以非常方便地调用API了。有兴趣的童鞋可以试试写出来。 __call__ 一个对象实例可以有自己的属性和方法,当我们调用实例方法时,我们用instance.method()来调用。能不能直接在实例本身上调用呢?在Python中,答案是肯定的。 任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。请看示例: class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name) 调用方式如下: >>> s = Student('Michael') >>> s() # self参数不要传入 My name is Michael. __call__()还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。 如果你把对象看成函数,那么函数本身其实也可以在运行期动态创建出来,因为类的实例都是运行期创建出来的,这么一来,我们就模糊了对象和函数的界限。 那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call__()的类实例: >>> callable(Student()) True >>> callable(max) True >>> callable([1, 2, 3]) False >>> callable(None) False >>> callable('str') False 通过callable()函数,我们就可以判断一个对象是否是“可调用”对象。 小结 Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类。 转载。原文:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319098638265527beb24f7840aa97de564ccc7f20f6000

优秀的个人博客,低调大师

面向对象高级编程:使用@property

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改: s = Student() s.score = 9999 这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数: class Student(object): def get_score(self): return self._score def set_score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value 现在,对任意的Student实例进行操作,就不能随心所欲地设置score了: >>> s = Student() >>> s.set_score(60) # ok! >>> s.get_score() 60 >>> s.set_score(9999) Traceback (most recent call last): ... ValueError: score must between 0 ~ 100! 但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。 有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的! 还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的: class Student(object): @property def score(self): return self._score @score.setter def score(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value @property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作: >>> s = Student() >>> s.score = 60 # OK,实际转化为s.set_score(60) >>> s.score # OK,实际转化为s.get_score() 60 >>> s.score = 9999 Traceback (most recent call last): ... ValueError: score must between 0 ~ 100! 注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。 还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性: class Student(object): @property def birth(self): return self._birth @birth.setter def birth(self, value): self._birth = value @property def age(self): return 2015 - self._birth 上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。 小结 @property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。 转载。原文:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143186781871161bc8d6497004764b398401a401d4cce000

优秀的个人博客,低调大师

《Java编程思想》读书笔记(6)

JButton这一章,Brucke只给出了一个简单的例子,代码如下: import java.applet.Applet; import java.awt.*; import javax.swing.*; public class Test extends JApplet { private JButton btn1; private JButton btn2; /** * @param args */ public void init() { this.btn1 = new JButton("确定"); this.btn2 = new JButton("重置"); Container con = this.getContentPane(); con.setLayout(new FlowLayout()); con.add(btn1); con.add(btn2); } public static void main(String[] args) { Test t1 = new Test(); Console.run(t1,300,300); } } 这一节没有过多的东西可以思考,但布局管理器的知识值得去深究。 Java语言中提供的布局管理器种类有:边界式布局、卡片式布局、流式布局和网格式布局等,各有不同的特点,可根据实际 需要选用;但有最大自由设计空间的是“无布局管理器”——即不使用任何布局格式,而通过手工方式添加组件到页面布局的绝对位置上。因此我采用“无布局管理器”将他的代码改写如下: import java.applet.Applet; import java.awt.*; import javax.swing.*; public class Test extends JApplet { private JButton btn1; private JButton btn2; /** * @param args */ public void init() { this.btn1 = new JButton("确定"); this.btn2 = new JButton("重置"); Container con = this.getContentPane(); //con.setLayout(new FlowLayout()); con.setLayout(null); btn1.reshape(30,30,100,100); btn2.reshape(150,150,100,100); con.add(btn1); con.add(btn2); } public static void main(String[] args) { Test t1 = new Test(); Console.run(t1,600,600); } } 1. GridLayout GridLayout类是布局管理器之一,它将容器中的组件在放置在一个矩形网格中。容器被划分为相同大小的矩形,而每个组件就放置在一个单独的矩形中。 import java.awt.*; import javax.swing.*; public class GridForm extends JFrame { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub GridForm gf = new GridForm(); gf.setLayout(new GridLayout(3,2)); Container con = gf.getContentPane(); con.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); con.add(new JButton("1")); con.add(new JButton("2")); con.add(new JButton("3")); con.add(new JButton("4")); con.add(new JButton("5")); con.add(new JButton("6")); gf.setTitle("GridLayout例子"); gf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); gf.setSize(200,200); gf.setVisible(true); } } 如果容器的ComponentOrientation属性是水平的并且从左到右,上面例子产生如下图1: 如果容器的ComponentOrientation属性是horizontal 和 right-to-left,结果就如下图2: 当行数和列数都被设置为非零值(不管是通过构造函数或者通过setRows和setColumns方法来设置),指定的列数就会被忽略掉。例如说,如果指定是3行3列,而将布局中放置9个组件,它们就会显示为3行3列。 2.BorderLayout 边界布局会把容器看成五个:部分:north, south, east, west,和 center。每个区域最多包含一个组件,重要的五个常量:NORTH, SOUTH, EAST, WEST和 CENTER; Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add(new Button("Okay"), BorderLayout.SOUTH); ================================================== ================================================== Panel p2 = new Panel(); p2.setLayout(new BorderLayout()); p2.add(new TextArea()); // Same as p.add(new TextArea(), BorderLayout.CENTER); <!--[endif]--> BorderLayout 支持相对定位常量, PAGE_START, PAGE_END, LINE_START, and LINE_END. 在一个容器中,如果它的 ComponentOrientation 被设置为ComponentOrientation.LEFT_TO_RIGHT,这些常量就分别映射为 NORTH, SOUTH, WEST, and EAST 为了与以前兼容,BorderLayout也好汉相对定位常量 BEFORE_FIRST_LINE, AFTER_LAST_LINE, BEFORE_LINE_BEGINS and AFTER_LINE_ENDS. 他们分别和PAGE_START, PAGE_END, LINE_START and LINE_END等价. 如果同时使用绝对定位和相对定位,就会产生不可预测的结果。例如,如果你在容器中同时使 NORTH 和 PAGE_START 常量 来添加组件,而容器的 方向是 LEFT_TO_RIGHT, 那么就只有PAGE_START被会布局。 import java.awt.*; import javax.swing.*; public class GridForm extends JFrame { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub GridForm gf = new GridForm(); gf.setLayout(new BorderLayout()); Container con = gf.getContentPane(); con.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); con.add(new JButton("North"),BorderLayout.NORTH); con.add(new JButton("SOUTH"),BorderLayout.SOUTH); con.add(new JButton("EAST"),BorderLayout.EAST); con.add(new JButton("WEST"),BorderLayout.WEST); con.add(new JButton("CENTER"),BorderLayout.CENTER); gf.setTitle("BorderLayout例子"); gf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); gf.setSize(200,200); gf.setVisible(true); } } 3. FlowLayout FlowLayout会将组件从左到右进排列,就象文章中的文本行一样。流布局一般用在面板中的按纽的放置。它将会将按纽以从左至右的方式排放,直到在同一行中再也放不下更多的按纽了。 import java.awt.*; import javax.swing.*; public class GridForm extends JFrame { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub GridForm gf = new GridForm(); //gf.setLayout(new BorderLayout()); gf.setLayout(new FlowLayout()); Container con = gf.getContentPane(); con.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); con.add(new JButton("North")); con.add(new JButton("SOUTH")); con.add(new JButton("EAST")); con.add(new JButton("WEST")); con.add(new JButton("CENTER")); gf.setTitle("FlowLayout例子"); gf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); gf.setSize(200,200); gf.setVisible(true); } } 4.BoxLayout BoxLayout能让你在垂直和水平两个方向上控制组件的摆放,它用一些被称为支柱(struts)和胶水(glue)的东西来控制组件间的距离。 package com.vitamin.UI; import javax.swing.*; import java.awt.*; import com.vitamin.*; import com.vitamin.Console.console; public class BoxLayout1 extends JApplet { public void init() { JPanel jpv = new JPanel(); jpv.setLayout(new BoxLayout(jpv, BoxLayout.Y_AXIS)); for(int i = 0; i < 5; i++) jpv.add(new JButton("jpv " + i)); JPanel jph = new JPanel(); jph.setLayout(new BoxLayout(jph, BoxLayout.X_AXIS)); for(int i = 0; i < 5; i++) jph.add(new JButton("jph " + i)); Container cp = getContentPane(); cp.add(BorderLayout.EAST, jpv); cp.add(BorderLayout.SOUTH, jph); } public static void main(String[] args) { console.run(new BoxLayout1(), 450, 200); } } 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2006/06/01/415342.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《Java编程思想》读书笔记(10)

package com.vitamin.UI; import javax.swing.*; import javax.swing.filechooser.FileFilter; import java.awt.BorderLayout; import java.awt.Container; import java.awt.GridLayout; import java.awt.event.*; import java.io.File; import java.io.FileWriter; import java.io.IOException; import com.vitamin.Console.*; public class FileTest extends JFrame { private JButton btnOpen = new JButton("Open"); private JButton btnSave = new JButton("Save"); private JPanel p = null; private JTextField tfDir = new JTextField(); private JTextField tfFileName = new JTextField(); private JScrollPane sp = new JScrollPane(); private JEditorPane ep = new JEditorPane(); private File file = null; public FileTest() { super(); // TODO Auto-generated constructor stub this.initForm(); } public void initForm() { Container con = this.getContentPane(); con.setLayout(new BorderLayout()); this.tfDir.setEditable(false); this.tfFileName.setEditable(false); this.btnSave.setEnabled(false); this.btnOpen.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { JFileChooser fc = new JFileChooser(); fc.setFileFilter(new TextFileFilter() ); int returnVal = fc.showOpenDialog(FileTest.this); if(returnVal == JFileChooser.APPROVE_OPTION) { file = fc.getSelectedFile(); try { ep.setPage(file.toURL()); tfFileName.setText(file.getAbsolutePath()); btnSave.setEnabled(true); } catch(IOException ex) { throw new RuntimeException(ex); } } else if(returnVal == JFileChooser.CANCEL_OPTION) { tfFileName.setText("你已经取消了文件的选择"); } } }); this.btnSave.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { try { FileWriter fw = new FileWriter(file); ep.write(fw); JOptionPane.showMessageDialog(FileTest.this,"保存成功"); } catch (IOException ioe) { throw new RuntimeException(ioe); } } }); sp.getViewport().add(ep); p = new JPanel(); p.add(this.btnOpen); p.add(this.btnSave); con.add(p,BorderLayout.SOUTH); con.add(sp,BorderLayout.CENTER); p = new JPanel(); p.setLayout(new GridLayout(2,1)); p.add(this.tfDir); p.add(this.tfFileName); con.add(p,BorderLayout.NORTH); console.run(this,400,400); } public class TextFileFilter extends javax.swing.filechooser.FileFilter { public boolean accept(File f) { return f.getName().endsWith(".txt") || f.isDirectory(); } public String getDescription() { return "Text Files (*.txt)"; } } /** * @param args */ public static void main(String[] args) { FileTest ft = new FileTest(); } } 做了个读写文件的小东西,功能很烂,有时间做个完整的记事本吧。 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2006/06/08/420130.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《Java编程思想》读书笔记(8)

前面的几篇笔记都写得太古板了,今天就换个新的写作风格来试试,暂且叫“案例导向式”吧,希望能对自己和别人的学习有所帮助。 第一部分 问题场景描述 某日,小菜跑来问我:“phinecos,我真是快被java逼疯了,你可得帮帮我呀!!“ 我转过头,“怎么了,小菜?“。 “是这样的,我现在在学习swing,每次用一个控件吧,如果想知道它能处理的事件的话,就得去查jdk文档,可sun那该死的文档总是把人搞得头晕,我只不过是想看看有什么事件可以处理而已,它那乱七八糟的文档反而把我快逼疯了,你给我出出主意吧。。。“小菜着急地摇着我的手说。 “哦,原来是这样啊,恩,可为什么你不用eclipse哪?它有提供你所需要的功能啊。”我不解的问。 “。。。这个,我不是不想用啊,可听人说,高手都是只用记事本和jdk的,我想成为高手,所以不敢用呀。”小菜支支唔晤的说。 “。。。。。。” 第二部分 分析与设计 需求是软件的关键。碰到上面小菜的问题了,我们就开始进行分析吧。小菜到底有什么需求哪?他是想查看一个swing控件类能够处理的事件列表,也就是它的所有addXXXListener方法。怎么办哪?看来只有两个解决方案了:一,劝小菜用eclipse,这样就可以直接利用eclipse的功能满足他的需求。(可这个已经被否定了,因为小菜要成为“高手”,^o^).二,那就只有为他开发一个小实用工具,让他可以查看各个Swing控件能够处理的事件,也就是把它的所有addXXXListener方法都列出来。 好了,东西比较小,那就先从GUI界面开始,至于核心的事件处理先不管,如下图: 6-6-1.GIF 用户界面代码如下: package com.vitamin.UI; import java.awt.ActiveEvent; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Event; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import com.vitamin.Console.console; public class ShowAddListeners extends JFrame { private JLabel lbName = null; private JTextField tfName = null; private JTextArea tResult = null; private JPanel pName = null; public ShowAddListeners() { super(); this.initForm(); } public ShowAddListeners(String title) { super(title); this.initForm(); } private void initForm() { this.lbName = new JLabel("请输入Swing控件的类名:"); this.tfName = new JTextField(20); this.tResult = new JTextArea(40,50); this.pName = new JPanel(); pName.add(this.lbName); pName.add(this.tfName); Container con = this.getContentPane(); con.add(BorderLayout.NORTH,pName); con.add(new JScrollPane(this.tResult)); tfListener tf1 = new tfListener(); this.tfName.addActionListener(tf1); console.run(this,600,600); } class tfListener implements ActionListener { public void actionPerformed(ActionEvent e) {//核心处理代码处 if(tfName.getText().length()==0) { JOptionPane.showMessageDialog((JTextField)e.getSource(),"请输入控件类名称!!!","错误信息",JOptionPane.DEFAULT_OPTION); return; } JOptionPane.showMessageDialog((JTextField)e.getSource(),"OK","信息",JOptionPane.DEFAULT_OPTION); } } /** * @param args */ public static void main(String[] args) { ShowAddListeners sl = new ShowAddListeners("事件查看器"); } } 在这里我对用户引发的键盘事件还只是简单地进行一个测试用的显示处理,还没有添加进用来完成所需功能的代码,但提早让用户体验到模型,哪怕是一个没有具体功能的虚模型也是一件好事情。 恩,问题来了,接收到用户输入的swing控件类名以后,该怎么去读取它所有的方法,并且能把adeeXXXListener()这样类型的方法给显示在TextArea控件里给用户哪?我第一反应是:要想获取一个类的所有方法,应该用RTTI,先用类名构造一个Class,再去尝试获取其方法。至于想从读出来的所有方法中只选出adeeXXXListener()类型的方法,应该要使用正则表达式来进行模式匹配吧。现有的思路是这样的,可对RTTI, 正则表达式,我都不熟悉,该怎么办哪?看来得靠jdk文档和google了。 好吧,打开jdk文档开始看Class的知识吧: public static Class<?> forName(String className) throws ClassNotFoundException 返回与带有给定字符串名的类或接口相关联的 Class 对象。调用此方法等效于: Class.forName(className, true, currentLoader) 其中 currentLoader 表示此类的定义类加载器。 例如,以下代码片段返回 java.lang.Thread 类的运行时 Class 描述符。 Class t = Class.forName("java.lang.Thread") 调用 forName("X") 将导致名为 X 的类被初始化。 恩,正是我要的,仿上面给的例子,我应该这样做:先获取用户输入的swing控件名称,如JButton,然后:] Class t= Class.forName("java.swing."+name); 现在有了运行时的类了,接下来就是获取它的所有方法了 那我就应该这样:Method[] mt = t. getMethod();这样就把所有的方法读取到数组mt中了。 修改后的效果: 6-6-3.GIF 修改后的事件处理代码: class tfListener implements ActionListener { public void actionPerformed(ActionEvent e) { String name = tfName.getText().trim(); Class clName = null; if(name.length()==0) { JOptionPane.showMessageDialog((JTextField)e.getSource(),"请输入控件类名称!!!","错误信息",JOptionPane.DEFAULT_OPTION); return; } else { try { clName = Class.forName("javax.swing."+name); Method[] mt = clName.getMethods(); for(int i=0;i<mt.length;i++) { tResult.append(mt[i].toString()+"\n"); } } catch(ClassNotFoundException ex) { tResult.setText("没有找到匹配的方法名!!!"); } } } } 现在已经初具雏形了,可获取的是全部方法,并不是我们原本想要的东西,还得从这个方法列表中进行一些筛选工作才行。 要选出只含有addXXXListener的方法,就应该尝试构造一个能够识别这样方法的正则表达式。翻阅jdk文档后,我写了这样一个正则表达式: private static String StrReg = "add\\w+?Listener";其中\\w+?表示一个或多个字符 为了学习如何编写识别一个简单模式的程序,我写了一个简单的测试程序: package com.vitamin.Console; import java.util.regex.*; public class regTest { public static void main(String[] args) { Pattern p = null; Matcher m = null; p = Pattern.compile("a*b"); m = p.matcher("aaaaab"); if(m.matches()==true) { System.out.println("模式匹配成功"); } else { System.out.println("匹配失败"); } } } 现在就来完成剩余的工作,代码如下: package com.vitamin.UI; import java.awt.ActiveEvent; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Event; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Method; import java.util.regex.*; import javax.swing.*; import com.vitamin.Console.console; public class ShowAddListeners extends JFrame { private JLabel lbName = null; private JTextField tfName = null; private JTextArea tResult = null; private JPanel pName = null; private static String StrReg = "add\\w+?Listener"; private static Pattern pt = Pattern.compile(StrReg); private static Matcher mc = null; public ShowAddListeners() { super(); this.initForm(); } public ShowAddListeners(String title) { super(title); this.initForm(); } private void initForm() { this.lbName = new JLabel("请输入Swing控件的类名:"); this.tfName = new JTextField(20); this.tResult = new JTextArea(40,50); this.pName = new JPanel(); pName.add(this.lbName); pName.add(this.tfName); Container con = this.getContentPane(); con.add(BorderLayout.NORTH,pName); con.add(new JScrollPane(this.tResult)); tfListener tf1 = new tfListener(); this.tfName.addActionListener(tf1); console.run(this,600,600); } class tfListener implements ActionListener { public void actionPerformed(ActionEvent e) { String name = tfName.getText().trim(); Class clName = null; if(name.length()==0) { JOptionPane.showMessageDialog((JTextField)e.getSource(),"请输入控件类名称!!!","错误信息",JOptionPane.DEFAULT_OPTION); return; } else { try { clName = Class.forName("javax.swing."+name); Method[] mt = clName.getMethods(); for(int i=0;i<mt.length;i++) { mc = pt.matcher(mt[i].toString()); if(mc.find()) { tResult.append(mt[i].toString()+"\n"); } } } catch(ClassNotFoundException ex) { tResult.setText("没有找到匹配的方法名!!!"); } } } } /** * @param args */ public static void main(String[] args) { ShowAddListeners sl = new ShowAddListeners("事件查看器"); } } 结果如下,虽然还有很多地方不成熟,但也算是我的一个小作品吧,^o^ 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2006/06/06/418261.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《Java编程思想》读书笔记(14)

程序是根据具体情况在不断地创建新对象,而这些情况又只有在运行时才能够确定,因此我们就不知道到底需要多少对象,什么类型的对象,所以要能够创建任何对象并且能保持住这些对象的引用。Java就提供了很多容器类来持有和操纵对象。 数组是比较特别的一个容器,怎么说呢,它可以持有象int等基本类型数据,能够随机存储和访问,而且访问效率很高,但高效率是以牺牲灵活为代价的,当你创建了一个数组后,它的容量就确定了,并且在其生命周期内不能改变。而与它相对应的ArrayList就恰好相反,它可以灵活地增加容量,但效率就明显低于数组。而与List,Map,Set等泛型容器相比,数组在创建时就指明了它持有的对象类型,因此在编译时就会做类型检查,从而防止插入错误类型的对象。而泛型容器把它里面的元素都看成是Object,因此能容纳所有类型的对象(这就郁闷了,当你要往里面插入基本类型的数据时,就不得不先用对应的包装类将基本类型包装为Object型),并且泛型容器也没有编译时的类型检查,因此安全性得不到保证。 本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2006/06/17/428251.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册