- 浏览: 131269 次
- 性别:
- 来自: 珠海
-
文章分类
最新评论
-
txxxs:
...
Spring学习笔记:1、概念理解(转载) -
bfyycdi:
精确这个词有误导意义啊,IEEE的浮点也不是精确的啊!
Java中的strictfp关键字 -
xiaguangme:
xiaguangme 写道strictfp 在类中,是可以用来 ...
Java中的strictfp关键字 -
xiaguangme:
strictfp 在类中,是可以用来修饰方法的
Java中的strictfp关键字 -
dracularking:
翻译成浮点严格更好一点
Java中的strictfp关键字
Java基础:
对象的集合(上)
1.数组:数组与其它容器的区别体现在三个方面:效率,类型识别以及可以持有primitives。数组是 Java 提供的,能随机存储和访问 reference 序列的诸多方法中的,最高效的一种。数组是一个简单的线性序列,所以它可以快速的访问其中的元素。但是速度是有代价的;当你创建了一个数组之后,它的容量就固定了,而且在其生命周期里不能改变。java泛型容器类还包括 List,Set 和 Map。它们处理对象的时候就好像这些对象都没有自己的具体类型一样。也就是说,容器将它所含的元素都看成是(Java 中所有类的根类)Object 的。这样你只需创建一种容器,就能把所有类型的对象全都放进去。与其他泛型容器相比,这里体现出数组的第二个优势:创建数组的时候,你也同时指明了它所持有的对象的类型(这又引出了第三点 —— 数组可以持有 primitives,而容器却不行)。也就是说,它会在编译的时候作类型检查,从而防止你插入错误类型的对象,或者是在提取对象的时候把对象的类型给搞错了。
2.数组是第一流的对象:不管你用的是那种类型的数组,数组的标识符实际上都是一个“创建在堆(heap)里的实实在在的对象的”reference。实际上是那个对象持有其他对象的 reference。reference(Object) 数组与primitives 数组不同的是对象数组持有 reference,而 primitive 数组则直接持有值。
import com.bruceeckel.simpletest.*; class Weeble {} // A small mythical creature public class ArraySize { public static void main(String[] args) { // Arrays of objects: Weeble[] a; // Local uninitialized variable Weeble[] b = new Weeble[5]; // Null references Weeble[] c = new Weeble[4];//数组的定义方式1 for(int i = 0; i < c.length; i++) if(c[i] == null) // Can test for null reference c[i] = new Weeble( ); // Aggregate initialization: Weeble[] d = {new Weeble( ), new Weeble( ), new Weeble( )};//数组的定义方式2 // Dynamic aggregate initialization: a = new Weeble[] {new Weeble( ), new Weeble( )};//数组的定义方式3 System.out.println("a.length=" + a.length); System.out.println("b.length = " + b.length); // The references inside the array are // automatically initialized to null: for(int i = 0; i < b.length; i++) System.out.println("b[" + i + "]=" + b[i]);//就算b里没有值也可以输出,只不过是null而已, //最重要的是Weeble[] b = new Weeble[5];分配了空间 System.out.println("c.length = " + c.length); System.out.println("d.length = " + d.length); a = d;//改变了a的指向 System.out.println("a.length = " + a.length); // Arrays of primitives: int[] e; // Null reference int[] f = new int[5];//数组的定义方式1 int[] g = new int[4]; for(int i = 0; i < g.length; i++) g[i] = i*i; int[] h = { 11, 47, 93 };//数组的定义方式2 // Compile error: variable e not initialized: //!System.out.println("e.length=" + e.length); System.out.println("f.length = " + f.length); // The primitives inside the array are // automatically initialized to zero: for(int i = 0; i < f.length; i++) System.out.println("f[" + i + "]=" + f[i]); System.out.println("g.length = " + g.length); System.out.println("h.length = " + h.length); e = h;//改变了e的指向 System.out.println("e.length = " + e.length); e = new int[] { 1, 2 };//数组的定义方式3 System.out.println("e.length = " + e.length); } } ///:~
3.返回一个数组:假设你写了一个方法,它返回的不是一个而是一组东西。在 C 和 C++之类的语言里,这件事就有些难办了。因为你不能返回一个数组,你只能返回一个指向数组的指针。由于要处理“控制数组生命周期”之类的麻烦事,这么做很容易会出错,最后导致内存泄漏。Java 采取了类似的解决方案,但是不同之处在于,它返回的“就是一个数组”。与 C++不同,你永远也不必为 Java 的数组操心——只要你还需要它,它就还在;一旦你用完了,垃圾回收器会帮你把它打扫干净。(也就是说你可以把不同类型的东西同时都塞到一个数组里进行返回,只要你知道那个是哪个就行。这种情况也可以适合Java的其他容器里)
import com.bruceeckel.simpletest.*; import java.util.*; public class IceCream { private static Random rand = new Random( ); public static final String[] flavors = { "Chocolate", "Strawberry", "Vanilla Fudge Swirl", "Mint Chip", "Mocha Almond Fudge", "Rum Raisin", "Praline Cream", "Mud Pie" }; public static String[] flavorSet(int n) { String[] results = new String[n]; boolean[] picked = new boolean[flavors.length]; for(int i = 0; i < n; i++) { int t; do t = rand.nextInt(flavors.length); while(picked[t]); results[i] = flavors[t]; picked[t] = true; } return results; } public static void main(String[] args) { for(int i = 0; i < 20; i++) { System.out.println( "flavorSet(" + i + ") = "); String[] fl = flavorSet(flavors.length); for(int j = 0; j < fl.length; j++) System.out.println("\t" + fl[j]); } } } ///:~
4.Arrays 类:java.util 里面有一个 Arrays 类,它包括了一组可用于数组的 static方法,这些方法都是一些实用工具。其中有四个基本方法:用来比较两个数组是否相等的 equals( );用来填充数组的 fill( );用来对数组进行排序的 sort( );以及用于在一个已排序的数组中查找元素的binarySearch( )。所有这些方法都对 primitive 和 Object 进行了重载。此外还有一个 asList( )方法,它接受一个数组,然后把它转成一个List 容器。
(1)fill( )方法,但是它太简单了;它只是简单的把一个的值复制到数组各个位置,如果是对象,则将相同的reference 拷贝到每个位置,如:
int[] a5 = new int[10]; Arrays.fill(a5, 19);//a5数组的每个位置都是19 String[] a9 = new String[10]; Arrays.fill(a9, "Hello");//a9数组的每个位置都是"Hello" Arrays.fill(a9, 3, 5, "World");//用"World"来填充a[3],a[4],包前不包后。
(2)java 标准类库提供了一个 System.arraycopy( )的 static 方法。相比 for 循环,它能以更快的速度拷贝数组。如:
int[] i = new int[7]; int[] j = new int[10]; Arrays.fill(i, 47); Arrays.fill(j, 99); System.arraycopy(i, 1, j, 0, i.length-1);//把i考到j里,1为i的下标,0为j的开始下标,i.length-1为j的结束下标
(3)Arrays 提供了经重载的 equals( )方法。当然,也是针对各种 primitive 以及 Object 的。两个数组要想完全相等,它们必须有相同数量的元素,而且数组的每个元素必须与另一个数组的相对应的位置上的元素相等。元素的相等性,用 eqauls( )判断。(对于 primitive,它会使用其 wrapper 类的 equals( );比如 int 使用Integer.equals( )。)例如:
import com.bruceeckel.simpletest.*; import java.util.*; public class ComparingArrays { public static void main(String[] args) { int[] a1 = new int[10]; int[] a2 = new int[10]; Arrays.fill(a1, 47); Arrays.fill(a2, 47); System.out.println(Arrays.equals(a1, a2)); a2[3] = 11; System.out.println(Arrays.equals(a1, a2)); String[] s1 = new String[5]; Arrays.fill(s1, "Hi"); String[] s2 = {"Hi", "Hi", "Hi", "Hi", "Hi"}; System.out.println(Arrays.equals(s1, s2));//数组是否相等是基于其内容,(通过 Object.equals( )),} } ///:~
(4)Arrays.sort(a)可以对数组a(a可以为任何的数组)进行排序.内置的排序方法能对任何数组排序,不论是 primitive的还是对象数组,只要它实现了 Comparable 接口或有一个与之相关的 Comparator(针对对象数组,primitive 数组不允许使用 Comparator)接口就行了。[1]:Comparable 接口,要重写一个方法 compareTo( ),这个方法能接受另一个对象作为参数,如果现有对象比参数小,它会返回一个负数,如果相同则返回零,如果现有的对象比参数大,它就返回一个正数。[2]Comparator 接口,有两个方法 compare( )和 equals( )。但是除非是有特殊的性能要求,否则你用不着去实现 equals( )。因为只要是类,它就都隐含地继承自Object,而 Object 里面已经有了一个 equals( )了。所以你尽可以使用缺省的 Object 的 equals( ),这样就已经满足接口的要求了。 Arrays.asList( )方法把数组改造成 List:如
List a = Arrays.asList("one two three four five six seven eight".split(" "));
例子[1]:
import com.bruceeckel.util.*; import java.util.*; public class CompType implements Comparable { int i; int j; public CompType(int n1, int n2) { i = n1; j = n2; } public String toString( ) { return "[i = " + i + ", j = " + j + "]"; } public int compareTo(Object rv) { int rvi = ((CompType)rv).i; return (i < rvi ? -1 : (i == rvi ? 0 : 1)); } private static Random r = new Random( ); public static Generator generator( ) { return new Generator( ) { public Object next( ) { return new CompType(r.nextInt(100),r.nextInt(100)); } }; } public static void main(String[] args) { CompType[] a = new CompType[10]; Arrays2.fill(a, generator( )); System.out.println( "before sorting, a = " + Arrays.asList(a)); Arrays.sort(a); System.out.println("after sorting, a = " + Arrays.asList(a)); } } ///:~
如果CompType 没有实现 Comparable 接口,那么程序运行调用到sort( )的时候,就会引发一个 ClassCastException 错误。这是因为sort( )会把传给它的参数转换成 Comparable。
例子[2]:
import com.bruceeckel.util.*; import java.util.*; class CompTypeComparator implements Comparator { public int compare(Object o1, Object o2) { int j1 = ((CompType)o1).j; int j2 = ((CompType)o2).j; return (j1 < j2 ? -1 : (j1 == j2 ? 0 : 1)); } } public class ComparatorTest { public static void main(String[] args) { CompType[] a = new CompType[10]; Arrays2.fill(a, CompType.generator( )); System.out.println("before sorting, a = " + Arrays.asList(a)); Arrays.sort(a, new CompTypeComparator( ));//利用Comparator比较方法来排列a数组, //因为自动调用compare方法 System.out.println("after sorting, a = " + Arrays.asList(a)); } } ///:~
(5)查询有序数组,一旦数组排完序,你就能用 Arrays.binarySearch( )进行快速查询了。但是切忌对一个尚未排序的数组使用 binarySearch( );因为这么做的结果是没意义的。如果 Arrays.binarySearch( )找到了,它就返回一个大于或等于 0
的值。否则它就返回一个负值,而这个负值要表达的意思是,如果你手动维护这个数组的话,这个值应该插在哪个位置。这个值就是:(插入点)-1, “插入点”就是,在所有“比要找的那个值”更大值中,最小的那个值的下标,或者,如果数组中所有的值都比要找的值小,它就是a.size( )。如果数组里面有重复元素,那它不能保证会返回哪一个。如果排序的时候用到了 Comparator ,那么binarySearch( )的时候,也必须使用同一个 Comparator (用这个方法的重载版)。
import com.bruceeckel.simpletest.*; import com.bruceeckel.util.*; import java.util.*; public class AlphabeticSearch { public static void main(String[] args) { String[] sa = new String[30]; Arrays2.fill(sa, new Arrays2.RandStringGenerator(5)); CompTypeComparator comp = new CompTypeComparator( ); Arrays.sort(sa, comp);//利用了Comparator比较排序 int index = Arrays.binarySearch(sa, sa[10],comp);//也一定要用Comparator进行比较 System.out.println("Index = " + index); } } ///:~
(6)容器简介:Java 的容器类分成两种基本类型。它们的区别就在,每个位置能放多少对象。Collection 只允许每个位置上放一个对象(这个名字有点误导,因为容器类库也常被统称为 collections)。它包括“以一定顺序持有一组对象”的 List,以及“只能允许添加不重复的对象”的 Set。ArrayList 是一种 List,而 HashSet 则是一种 Set。你可以用 add( )方法往Collection 里面加对象。Map 保存的是“键(key)—值”形式的 pair,很像是一个微型数据库。上面这段程序用了一种叫HashMap 的 Map。如果你建了一个“州和首府”的 Map,然后想查一下 Ohio 的首府在哪里,你就可以用它来找了。用法和用下标查数组是一样的。(Map 又被称为关联性数组associative array。)你可以用 put( )方法往 Map 里面加元素。它接受键—值形式 pair 作参数。
List 会老老实实地持有你所输入的所有对象,既不做排序也不做编辑。Set 则每个对象只接受一次,而且还要用它自己的规则对元素进行重新排序(一般情况下,你关心的只是Set 包没包括某个对象,而不是它到底排在哪里——如果是那样,你最好还是用 List)。Map 也不接收重复的 pair,至于是不是重复,要由key 来决定。此外,它也有它自己的内部排序规则,不会受输入顺序影响。如果插入顺序是很重要的,那你就只能使用 LinkedHashSet 或LinkedHashMap 了。
Collection 和 Map 默认情况下的打印输出(使用容器类的 toString( )方法)的效果很不错
,所以我们就不再提供额外的打印支持了。打印出来的 Collection 会用方括号括起来,元素与元素之间用逗号分开。Map 会用花括号括起来,键和值之间用等号联起来(键在左边,值在右边)。
(7).容器的缺点:不知道对象的类型:Java 的容器有个缺点,就是往容器里面放对象的时候,会把对象的类型信息给弄丢了。这是因为开发容器类的程序员不会知道你要用它来保存什么类型的对象,而让容器仅只保存特定类型的对象又会影响它的通用性。所以容器被做成只持有 Object,也就是所有对象的根类的 reference,这样它就能持有任何类型的对象了。(当然不包括 primitive,因为它们不是对象,也没有继承别的对象。)这是一个很了不起的方案,只是:
[1]由于在将对象放入容器的时候,它的类型信息被扔掉了,所以容器对“能往里面加什么类型的对象”没有限制。比方说,即使你想让它只持有 cat,别人也能很轻易地把 dog 放进去。
[2]由于对象的类型信息没了,容器只知道它持有的 Object 的 reference,所以对象在使用之前(在容器里取出的时候)还必须进行类型转换。
(8)迭代器:“迭代器(iterator)”的概念(又是一个设计模式)就是用来达成这种抽象的。迭代器是一个对象,它的任务是,能在让“客户程序员在不知道,或者不关心他所处理的是什么样的底层序列结构”的情况下,就能在一个对象序列中前后移动,并选取其中的对象。java的iterator可做的事情:
[1]用 iterator( )方法叫容器传给你一个 Iterator 对象。第一次调用Iterator 的 next( )方法的时候,它就会传给你序列中的第一个元素。
[2]用 next( )方法获取序列中的下一个对象。
[3]用 hasNext( )方法查询序列中是否还有其他对象。
[4]用 remove( )方法删除迭代器所返回的最后一个元素。
package c11; public class Cat { private int catNumber; public Cat(int i) { catNumber = i; } public void id( ) { System.out.println("Cat #" + catNumber); } public String toString(){ System.out.println("Cat''id =" + catNumber); } } ///:~
package c11; import com.bruceeckel.simpletest.*; import java.util.*; public class CatsAndDogs2 { public static void main(String[] args) { List cats = new ArrayList( );//ArrayList是一个能够自动扩展的数组,但是他是一个List for(int i = 0; i < 7; i++) cats.add(new Cat(i)); Iterator e = cats.iterator( );//Iterator的创建方式 while(e.hasNext( ))//先用hasNext( )进行判断 ((Cat)e.next( )).id( ); System.out.println(e.next());//直接调用toString()方法. } } ///:~
(9)Collection 的功能:Collection 的所有功能,也就是你能用 Set 和 List做什么事(不包括从 Object 自动继承过来的方法)。
[1]boolean add(Object):确保容器能持有你传给它的那个参数。如果没能把它加进去,就返回 false。(这是个“可选”的方法,本章稍后会再作解释。)
[2]boolean addAll(Collection):加入参数 Collection 所含的所有元素。只要加了元素,就返回 true。(“可选”)
[3]void clear( ):清除容器所保存的所有元素。(“可选”)
[4]boolean contains(Object):如果容器持有参数 Object,就返回true。
[5]boolean containsAll(Collection):如果容器持有参数 Collection 所含的全部元素,就返回 true。
[6]boolean isEmpty( ):如果容器里面没有保存任何元素,就返回 true。
[7]Iterator iterator( ):返回一个可以在容器的各元素之间移动的 Iterator。
[8]boolean remove(Object):如果容器里面有这个参数 Object,那么就把其中的某一个给删了。只要删除过东西,就返回 true。(“可选”)
[9]boolean removeAll(Collection):删除容器里面所有参数 Collection 所包含的元素。只要删过东西,就返回true。(“可选”)。
[10]boolean retainAll(Collection):只保存参数 Collection 所包括的元素(集合论中“交集”的概念)。如果发生过变化,则返回 true。(“可选”)
[11]int size( ) :返回容器所含元素的数量。
[12]Object[] toArray( ):返回一个包含容器中所有元素的数组。
[13]Object[] toArray(Object[] a):返回一个包含容器中所有元素的数组,且这个数组不是普通的 Object 数组,它的类型应该同参数数组 a 的类型相同(要做类型转换)。
(10)List 的功能:ist 的基本用法是用 add( )加对象,用 get( )取对象,用iterator( )获取这个序列的 Iterator。
[1]List (接口):List 的最重要的特征就是有序;它会确保以一定的顺序保存元素。List 在 Collection 的基础上添加了大量方法,使之能在序列中间插入和删除元素。(只对 LinkedList 推荐使用。)List 可以制造ListIterator 对象,你除了能用它在 List 的中间插入和删除元素之外,还能用它沿两个方向遍历List。
[2]ArrayList*:一个用数组实现的 List。能进行快速的随机访问,但是往列表中间插入和删除元素的时候比较慢。ListIterator 只能用在反向遍历 ArrayList 的场合,不要用它来插入和删除元素,因为相比LinkedList,在 ArrayList 里面用ListIterator 的系统开销比较高。
[3]LinkedList:对顺序访问进行了优化。在 List 中间插入和删除元素的代价也不高。随机访问的速度相对较慢。(用ArrayList 吧。)此外它还有 addFirst( ),addLast( ),getFirst( ),getLast( ),removeFirst( )和 removeLast( )等方法(这些方法,接口和基类均未定义),你能把它当成栈(stack),队列(queue)或双向队列(deque)来用。
(11)Set 的功能:Set 的接口就是 Collection 的,所以不像那两个 List,它没有额外的功能。Set 会拒绝持有多个具有相同值的对象的实例(对象的“值”又是由什么决定的呢?这个问题比较复杂,我们以后会讲的)。
[1]Set (接口):加入 Set 的每个元素必须是唯一的;否则,Set 是不会把它加进去的。要想加进 Set,Object 必须定义 equals( ),这样才能标明对象的唯一性。Set 的接口和 Collection 的一模一样。Set 的接口不保证它会用哪种顺序来存储元素。
[2]HashSet*:为优化查询速度而设计的 Set。要放进HashSet 里面的 Object 还得定义hashCode( )。
[3]TreeSet:是一个有序的 Set,其底层是一棵树。这样你就能从 Set 里面提取一个有序序列了。
[4]LinkedHashSet(JDK 1.4): 一个在内部使用链表的 Set,既有 HashSet 的查询速度,又能保存元素被加进去的顺序去(插入顺序)。用 Iterator 遍历 Set 的时候,它是按插入顺序进行访问的。
HashSet 保存对象的顺序是和 TreeSet和 LinkedHashSet 不一样的。这是因为它们是用不同的方式来存储和查找元素的。(TreeSet 用了一种叫红黑树的数据结构『red-black treedata structure』来为元素排序,而 HashSet 则用了“专为快速查找而设计”的散列函数。LinkedHashSet 在内部用散列来提高查询速度,但是它看上去像是用链表来保存元素的插入顺序。)你写自己的类的时候,一定要记住,Set 要有一个判断以什么顺序来存储元素的标准,也就是说你必须实现 Comparable 接口,并且定义 compareTo( )方法。下面就是举例:
//: c11:Set2.java // Putting your own type in a Set. import com.bruceeckel.simpletest.*; import java.util.*; public class Set2 { public static Set fill(Set a, int size) { for(int i = 0; i < size; i++) a.add(new MyType(i)); return a; } public static void test(Set a) { fill(a, 10); fill(a, 10); // Try to add duplicates fill(a, 10); a.addAll(fill(new TreeSet( ), 10)); System.out.println(a); } public static void main(String[] args) { test(new HashSet( )); test(new TreeSet( )); test(new LinkedHashSet( )); } } ///:~
无论是用哪种 Set,你都应该定义 equals( ),但是只有在“要把对象放进 HashSet”的情况下,你才需要定义 hashCode( )(最好还是定义一个,因为通常情况下 HashSet 是 Set 的首选)。但是作为一种编程风格,你应该在覆写 equals( )的同时把 hashCode( )也覆写了。
SortedSet:SortedSet(只有 TreeSet 这一个实现可用)中的元素一定是有序的。这使得 SortedSet 接口多了一些方法(注意,SortedSet 意思是“根据对象的比较顺序”,而不是“插入顺序” 进行排序。):
[1]Comparator comparator( ):返回 Set 所使用的 Comparator对象,或者用 null 表示它使用 Object 自有的排序方法。
[2]Object first( ): 返回最小的元素。
[3]Object last( ): 返回最大的元素。
[4]SortedSet subSet(fromElement, toElement): 返回 Set 的子集,其中的元素从 fromElement 开始到toElement 为止(包括fromElement,不包括 toElement)。
[5]SortedSet headSet(toElement):返回 Set 的子集,其中的元素都应小于 toElement。
[6]SortedSet headSet(toElement):返回 Set 的子集,其中的元素都应大于 fromElement。
文章出处:http://www.diybl.com/course/3_program/java/javaxl/2008325/107281.html
发表评论
-
Java深度历险(二)——Java类的加载、链接和初始化
2011-01-14 11:18 1030Java深度历险(二)——Java类的加载、链接和初始化 在 ... -
Java深度历险(一)——Java字节代码的操纵
2011-01-14 11:15 1234Java深度历险(一)—— ... -
JAVA String字符串格式化
2010-09-21 17:00 6680JDK1.5中,String类新增了 ... -
java String日期格式转换
2010-07-01 14:00 1801SimpleDateFormat sdf = new Simp ... -
【JAVA事务】JAVA的事务处理总结
2010-06-30 16:00 1540一:什么是JAVA事务? ... -
org.tigris.subversion.javahl.ClientException: RA layer request failed
2010-04-29 14:05 4287org.tigris.subversion.javahl.Cl ... -
java对象的集合(下)
2010-02-25 16:30 844JAVA基础:对象的集合( ... -
Java集合类之Set()
2010-02-25 16:28 3500Java集合类 集合中存放的是对象的引用,而非对象本身 ,出 ... -
JAVA线程
2010-02-25 16:26 770Java的线程编程非常 ... -
对hashCode的一点简单认识
2009-06-25 10:29 903hashcode,一个不太好理解,也常被我们忽视的一个概念。然 ... -
Java中的strictfp关键字
2009-03-02 13:50 16321strictfp Strictfp —— ... -
实现Runnable为什么比继承Thread好
2009-03-02 13:48 3465这个问题是个常规问题, ... -
使用Runnable接口
2009-03-02 13:37 1495使用Runnable接口 开发线程应用程序的第二个方法是 ...
相关推荐
# 基于 Koa2 的 FEBLOG API ## 项目简介 FEBLOG API 是一个基于 Node.js 和 Koa2 框架的 RESTful API 服务器,支持多种关系型数据库(如 PostgreSQL、MySQL、MariaDB、SQLite、MSSQL),并使用 Sequelize 作为 ORM。项目支持跨域请求、JSON 数据传输、JWT 身份认证等功能,适用于构建前后端分离的应用。 ## 主要特性和功能 跨域支持通过配置支持跨域请求。 数据传输格式支持 applicationxwwwformurlencoded、multipartformdata、applicationjson 格式的 POST、PUT、DELETE 请求。 JWT 身份认证通过 JWT 实现用户身份认证。 数据库支持使用 Sequelize ORM 支持 PostgreSQL、MySQL、MariaDB、SQLite、MSSQL 等多种数据库。
存储器实验资料.zip
# 基于 Python 的知乎热榜爬虫及数据处理项目 ## 项目简介 本项目基于 Python 编程语言,旨在实现知乎热榜的定时跟踪以及相关数据的存储与查询操作。通过爬虫技术获取知乎热榜问题的详细信息,将数据存入数据库,同时提供一系列 SQL 查询示例帮助用户熟悉 SQL 基本语法,还包含使用 Selenium 实现 GPA 计算器的功能。 ## 项目的主要特性和功能 1. 知乎热榜爬虫定期爬取知乎热榜,获取问题摘要、描述、热度、访问人数、回答数量等基本信息,并将数据存入数据库。 2. 可定制爬虫逻辑用户可以选择删除已有代码从零开始编写,也可以完成代码填空实现相应功能。 3. GPA 计算器使用 Selenium 模拟点击登录 WebVPN,登录 info 并访问成绩单页面,查询成绩并计算每学期的绩点。 4. SQL 练习提供一系列基于 MySQL 数据库的 SQL 查询练习,帮助用户熟悉基本的 SQL 语法,如添加新列、数据填充、关键词查询等。
# 基于C语言的学生信息管理系统 ## 项目简介 这是一个基于文本界面的学生信息管理系统,旨在通过简单的文本输入实现学生信息的添加、查找、修改和删除操作。系统采用链表数据结构存储学生信息,并支持文件读写功能以持久化存储数据。 ## 项目的主要特性和功能 ### 主要特性 1. 文本界面操作用户通过控制台输入指令完成操作。 2. 链表数据结构使用链表存储学生信息,方便信息的添加和删除。 3. 文件操作支持将学生信息数据保存到文件,以及从文件中读取数据。 ### 功能详解 登录验证用户需输入正确的学号和密码才能进入系统。 主界面展示显示系统主菜单,包括学生信息查找、删除、添加、修改和录入等功能。 学生信息查找根据学号查找学生信息。 学生信息删除根据学号删除学生信息。 学生信息添加可以添加新的学生信息到系统中。 学生信息修改可以修改已存在的学生信息。 学生信息录入展示所有存储的学生信息。 辅助功能
# 基于VS Code的px到rpx转换工具 ## 项目简介 本项目是一款VS Code插件,旨在将前端代码里的单位px转换为rpx。当设计师在设计稿中使用px单位时,开发者能够借助该工具快速把代码中的px转换为小程序适用的rpx单位。它借助语法分析技术实现精准转换,避免误改其他属性里的px。 ## 项目的主要特性和功能 1. 自动转换功能能通过简单命令自动识别并转换style标签内所有声明中的px为rpx。 2. 精准转换利用语法分析,仅对真正的单位值进行转换,防止错误修改其他内容中的px字符。 3. 部分转换支持可选择部分样式代码进行转换,操作灵活便捷。 ## 安装使用步骤 假设用户已下载本项目源码文件且安装了VS Code环境。 1. 安装插件打开VS Code,进入侧边栏的扩展视图,搜索并安装“px2rpx”插件。 2. 重启VS Code安装完成后重启VS Code使插件生效。
test文件资包。传递使用
主控:AT89C52 显示:LCD1602 光照检测:光敏电阻 距离检测:超声波测距 远光灯 近光灯 按键(设置阈值) 1、使用光敏电阻实时检测环境光线强度,设置阈值判断是否开启远光灯; 2、利用超声波传感器测量迎面车辆距离,设置安全距离阈值,自动切换到近光灯; 3、加入延时功能(例如在检测到迎面车辆后等待3秒再切换灯光),以减少频繁切换,提升平滑性。 4、所选传感器模块、执行器模块、电源与接口电路等模块的型号需要是便宜的。
esp-idf-v5.3.2
内容概要:本文介绍了多个信息安全领域的实战项目,涵盖网络渗透测试、Web应用安全加固、企业安全策略制定与实施、恶意软件分析、数据泄露应急响应、物联网设备安全检测、区块链安全审计和云安全防护。每个项目都详细描述了其目标和具体实施步骤,包括信息收集、漏洞扫描、利用和修复、安全配置、风险评估、制度建设、培训教育、样本获取与分析、事件响应、遏制措施、调查取证、数据恢复、安全检测、架构分析、智能合约审计、共识机制审查、云环境评估、访问管理、网络安全防护等方面。 适合人群:信息安全从业者、IT管理人员、安全顾问、系统管理员、开发人员以及对信息安全感兴趣的人员。 使用场景及目标:①为信息安全从业人员提供实际操作指导,帮助其掌握不同场景下的安全防护技能;②为企业提供全面的信息安全保障方案,确保其信息系统和数据的安全性;③为开发人员提供安全编码和系统设计的最佳实践指南,提高应用程序的安全性;④为安全研究人员提供深入分析恶意软件和区块链系统的工具和方法。 阅读建议:读者可以根据自身需求选择感兴趣的部分进行深入学习,建议结合实际案例进行实践操作,同时关注最新的安全技术和法规要求,以确保所学知识与时俱进并能应用于实际工作中。
# 基于C语言和STM32F0系列微控制器的宏键盘系统 ## 项目简介 本项目是基于C语言和STM32F0系列微控制器开发的宏键盘系统。该系统可让用户自定义宏按键,实现快速输入或自动化任务,涵盖硬件的GPIO输入输出控制、USB通信以及中断处理等功能。 ## 项目的主要特性和功能 宏定义用户能通过定义keymappings.h文件中的宏按键,自定义按键行为。 USB通信利用STM32F0系列微控制器的USB库,支持HID类通信。 GPIO控制实现对键盘按键读取和发送操作的控制。 中断处理可处理按键状态变化、USB通信等外部中断请求。 电源管理对微控制器的睡眠、停止和待机等电源模式进行管理。 ## 安装使用步骤 ### 硬件准备 确保STM32F0系列微控制器(如STM32F042K6)的GPIO引脚、USB接口等硬件连接正确。 保证所有必要外设(如LED、按键)正确连接且可用。 ### 软件准备 下载并解压项目源代码。
内容概要:本文详细介绍了如何利用COMSOL Multiphysics软件构建熔池枝晶模型,用于模拟金属在凝固过程中枝晶的生长行为。主要内容涵盖三个关键模块:传热、流体流动和相场。通过定义相应的偏微分方程(如传热方程、Navier-Stokes方程和相场方程),设置适当的边界条件和初始条件,并进行多物理场耦合求解,最终实现了对熔池温度分布、速度场及枝晶生长过程的精确模拟。此外,还探讨了如何优化求解器配置、处理移动边界条件、引入各向异性效应以及提高计算效率的方法。 适合人群:从事材料科学、冶金工程、增材制造等领域研究的专业人士和技术人员。 使用场景及目标:适用于需要深入了解金属凝固过程中微观结构演变机制的研究项目,特别是在激光熔覆、焊接等工艺中,帮助研究人员预测和优化材料性能。 其他说明:文中不仅提供了详细的建模步骤指导,还包括一些实用技巧,如参数选择、网格划分策略、热源耦合方式等,有助于解决实际建模过程中可能遇到的问题。
内容概要:本文详细介绍了利用COMSOL Multiphysics进行地下二氧化碳封存仿真的方法和技术要点。主要内容涵盖两相流模块设置、温度场耦合、地层分层建模以及力学模块处理等方面。文中不仅提供了具体的数学模型和代码片段,如相对渗透率函数、热膨胀系数函数等,还分享了许多实际操作中的经验和教训,强调了不同物理场之间的相互作用及其对模拟结果的影响。 适合人群:从事地质工程、环境科学、石油工程等领域研究的专业人士,尤其是那些需要进行地下流体运移和储层特性研究的科研工作者。 使用场景及目标:适用于希望深入了解地下二氧化碳封存机制的研究人员,帮助他们掌握如何使用COMSOL软件构建复杂的多物理场耦合模型,从而更好地预测和评估二氧化碳封存的安全性和有效性。 其他说明:文章中提到的技术细节对于确保模拟精度至关重要,例如正确处理单位转换、选择合适的渗透率模型、考虑温度变化对岩石性质的影响等。此外,作者还提醒读者应注意避免一些常见的错误配置,以免导致不可靠的结果。
ENCAP 2023打分表
中国上市公司协会:2022年中国上市公司董事会秘书履职报告
内容概要:本文详细介绍了利用MATLAB遗传算法解决带有时间窗约束的电动车路径规划和充电优化问题。首先,构建了客户点、充电站以及电动车的基本参数模型,然后设计了一套完整的遗传算法框架,包括染色体编码、适应度函数、交叉变异操作等。适应度函数综合考虑了总行驶距离、时间窗违约、电量透支等多个因素。通过多次迭代优化,最终得到了较优的路径规划方案,并展示了实验结果的可视化图形。此外,文中还讨论了一些调参技巧和实际应用中的注意事项。 适合人群:具有一定编程基础和技术背景的研究人员、工程师,特别是从事智能交通系统、物流配送优化领域的专业人士。 使用场景及目标:适用于需要进行电动车路径规划和充电管理的实际应用场景,如城市物流配送公司。主要目标是在满足客户需求和服务质量的前提下,最小化运营成本,提高车辆利用率。 其他说明:文中提供了详细的代码实现步骤和部分实验数据,有助于读者理解和复现研究结果。同时提到了一些实用的小技巧,如适当放宽时间窗惩罚系数可以降低总成本等。
# 基于Arduino的超声波距离测量系统 ## 项目简介 本项目是一个基于Arduino平台的超声波距离测量系统。系统包含四个超声波传感器(SPS)模块,用于测量与前方不同方向物体的距离,并通过蜂鸣器(Buzz)模块根据距离范围给出不同的反应。 ## 项目的主要特性和功能 1. 超声波传感器(SPS)模块每个模块包括一个超声波传感器和一个蜂鸣器。传感器用于发送超声波并接收回波,通过计算超声波旅行时间来确定与物体的距离。 2. 蜂鸣器(Buzz)模块根据超声波传感器测量的距离,蜂鸣器会给出不同的反应,如延时发声。 3. 主控制器(Arduino)负责控制和管理所有传感器和蜂鸣器模块,通过串行通信接收和发送数据。 4. 任务管理通过主控制器(Arduino)的 loop() 函数持续执行传感器任务(Task),包括测距、数据处理和蜂鸣器反应。 ## 安装使用步骤 1. 硬件连接
内容概要:本文详细介绍了如何使用COMSOL进行偶极光源的建模与仿真。首先解释了偶极子光源的物理本质及其重要性,然后逐步指导读者完成从创建新模型、设置电流源、配置边界条件到最终结果分析的全过程。文中强调了关键步骤如正确设置电流分量、选择合适的边界条件(如PML)、合理划分网格以及如何解读远场辐射图等。此外,还提供了多个实用技巧和常见错误规避方法,帮助用户提高仿真的准确性和效率。 适合人群:从事光学仿真、电磁场研究的专业人士和技术爱好者。 使用场景及目标:适用于需要精确模拟微纳尺度下电磁波行为的研究项目,特别是涉及偶极子光源的应用场合。通过掌握这些技能,可以更好地理解和预测实际物理现象,从而为相关领域的科研工作提供有力支持。 其他说明:文章不仅涵盖了基本的操作流程,还包括了许多作者亲身经历的经验分享,使读者能够避开一些常见的陷阱并获得更好的仿真效果。同时,文中提供的代码片段可以帮助用户快速上手,将理论知识转化为具体实践。
内容概要:本文详细介绍了COMSOL Multiphysics在多种扩散模型中的应用,涵盖电化学、多孔介质中的流体运移、岩石裂隙中的浆液扩散等领域。通过具体的代码片段展示了如何模拟电双层纳米电极中的扩散、二氧化碳混相驱替、岩石裂隙中的浆液扩散以及三层顶板随机裂隙浆液扩散等过程。文中强调了COMSOL的强大多物理场耦合能力和灵活性,特别是在处理复杂系统如煤颗粒的吸附/解吸行为时的优势。此外,还讨论了模型参数调整、边界条件设置、数值稳定性等问题,并分享了一些实践经验和技术细节。 适合人群:从事电化学、地质工程、油气田开发等相关领域的科研人员和工程师。 使用场景及目标:①研究电化学过程中离子迁移和电荷分布的变化;②模拟二氧化碳在多孔介质中的运移规律,优化油气采收率;③分析浆液在岩石裂隙中的扩散规律,指导注浆工程的设计;④探讨煤颗粒的吸附/解吸行为,提升煤层气开采和CO2封存的效果。 其他说明:文中提供了大量具体的技术细节和代码片段,有助于读者理解和复现相关模型。同时,作者分享了许多实际操作中的经验和技巧,对于初学者和有一定经验的研究人员都有很高的参考价值。
内容概要:本文介绍了一种新颖的时序预测模型CPO-ELM-ABKDE,它结合了冠豪猪优化(CPO)、极限学习机(ELM)以及自适应带宽核密度估计(ABKDE),用于多变量时序预测和区间概率预测。首先,利用时间滑窗技术将原始数据转换为多变量输入矩阵,然后采用CPO优化ELM的输入权重和偏置,提高预测准确性并防止过拟合。接着,通过ABKDE对预测残差进行建模,生成自适应的概率预测区间。实验结果显示,该模型在电力负荷预测任务中表现出色,点预测R²达到0.97,95%置信区间的覆盖率达到92.3%。 适用人群:从事数据分析、机器学习研究的专业人士,尤其是关注时序预测及其应用的研究者和技术开发者。 使用场景及目标:适用于需要精确时序预测的应用场合,如电力系统负荷预测、金融市场价格走势预测等。主要目标是在确保较高预测精度的同时提供可靠的不确定度量化,帮助决策者更好地应对潜在的风险。 其他说明:文中提供了详细的代码实现步骤,包括数据预处理、模型搭建、训练优化以及结果评估等多个环节。此外,还讨论了不同优化算法之间的性能比较,并强调了本模型对于处理实际工业数据的良好适应性和稳定性。
Gitblit 1.9.3 是 Gitblit 这个 Git 服务器工具的一个特定版本(即 1.9.3 版)。 Gitblit 是一个基于 Java 的 Git 仓库管理服务器,它可以让你在局域网或服务器上搭建自己的 Git 仓库系统,主要用于团队协作中的代码托管、权限管理、项目浏览等功能。