当前位置: 首页 > 编程日记 > 正文

javassist学习笔记

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

介绍:www.javassist.org/

javassist、ASM 对比

1、javassist是基于源码级别的API比基于字节码的ASM简单。

2、基于javassist开发,不需要了解字节码的一些知识,而且其封装的一些工具类可以简单实现一些高级功能。比如HotSwaper。

3、ASM比javassist性能更快,灵活行也较高。

4、javassist提供者动态代理接口最慢,比JDK自带的还慢

性能对比

Framework        First time       Later times
Javassist             257                  5.2
BCEL                     473                  5.5
ASM                      62.4                 1.1

http://javatar.iteye.com/blog/814426

http://attis-wong-163-com.iteye.com/blog/1143181

参考手册:

1、读取和输出字节码

ClassPool pool = ClassPool.getDefault();

//会从classpath中查询该类

CtClass cc = pool.get("test.Rectangle");

//设置.Rectangle的父类

cc.setSuperclass(pool.get("test.Point"));

//输出.Rectangle.class文件到该目录中

cc.writeFile("c://");

//输出成二进制格式

//byte[] b=cc.toBytecode();

//输出并加载class 类,默认加载到当前线程的ClassLoader中,也可以选择输出的ClassLoader。

//Class clazz=cc.toClass();

这里可以看出,Javassist的加载是依靠ClassPool类,输出方式支持三种。

2、新增Class

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.makeClass("Point");

//新增方法

cc.addMethod(m);

//新增Field

cc.addField(f);

从上面可以看出,对Class的修改主要是依赖于CtClass 类。API也比较清楚和简单。

3、冻结Class

当CtClass 调用writeFile()、toClass()、toBytecode() 这些方法的时候,Javassist会冻结CtClass Object,对CtClass object的修改将不允许。这个主要是为了警告开发者该类已经被加载,而JVM是不允许重新加载该类的。如果要突破该限制,方法如下:

CtClasss cc = ...;

:

cc.writeFile();

cc.defrost();

cc.setSuperclass(...);    // OK since the class is not frozen.

当 ClassPool.doPruning=true的时候,Javassist 在CtClass object被冻结时,会释放存储在ClassPool对应的数据。这样做可以减少javassist的内存消耗。默认情况ClassPool.doPruning=false。例如

CtClasss cc = ...;

cc.stopPruning(true);

:

cc.writeFile();                             // convert to a class file.

// cc没有被释放

提示:当调试时,可以调用debugWriteFile(),该方法不会导致CtClass被释放。

4、Class 搜索路径

从上面可以看出Class 的载入是依靠ClassPool,而ClassPool.getDefault() 方法的搜索Classpath 只是搜索JVM的同路径下的class。当一个程序运行在JBoss或者Tomcat下,ClassPool Object 可能找到用户的classes。Javassist 提供了四种动态加载classpath的方法。如下

//默认加载方式如pool.insertClassPath(new ClassClassPath(this.getClass()));

ClassPool pool = ClassPool.getDefault();

//从file加载classpath

pool.insertClassPath("/usr/local/javalib")

//从URL中加载

ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");

pool.insertClassPath(cp);

//从byte[] 中加载

byte[] b = a byte array;

String name = class name;

cp.insertClassPath(new ByteArrayClassPath(name, b));

//可以从输入流中加载class

InputStream ins = an input stream for reading a class file;

CtClass cc = cp.makeClass(ins);

5、ClassPool

5.1 减少内存溢出

ClassPool是一个CtClass objects的装载容器。当加载了CtClass object后,是不会被ClassPool释放的(默认情况下)。这个是因为CtClass object 有可能在下个阶段会被用到。

当加载过多的CtClass object的时候,会造成OutOfMemory的异常。为了避免这个异常,javassist提供几种方法,一种是在上面提到的 ClassPool.doPruning这个参数,还有一种方法是调用CtClass.detach()方法,可以把CtClass object 从ClassPool中移除。例如:

CtClass cc = ... ;

cc.writeFile();

cc.detach();

另外一中方法是不用默认的ClassPool即不用 ClassPool.getDefault()这个方式来生成。这样当ClassPool 没被引用的时候,JVM的垃圾收集会收集该类。例如

//ClassPool(true) 会默认加载Jvm的ClassPath

ClassPool cp = new ClassPool(true);

// if needed, append an extra search path by appendClassPath()

5.2  级联ClassPools

javassist支持级联的ClassPool,即类似于继承。例如:

ClassPool parent = ClassPool.getDefault();

ClassPool child = new ClassPool(parent);

child.insertClassPath("./classes");

5.3 修改已有Class的name以创建一个新的Class

当调用setName方法时,会直接修改已有的Class的类名,如果再次使用旧的类名,则会重新在classpath路径下加载。例如:

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("Point");

cc.setName("Pair");

//重新在classpath加载

CtClass cc1 = pool.get("Point");

对于一个被冻结(Frozen)的CtClass object ,是不可以修改class name的,如果需要修改,则可以重新加载,例如:

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("Point");

cc.writeFile();

//cc.setName("Pair");    wrong since writeFile() has been called.

CtClass cc2 = pool.getAndRename("Point", "Pair");

6、Class loader

上面也提到,javassist同个Class是不能在同个ClassLoader中加载两次的。所以在输出CtClass的时候需要注意下,例如:

// 当Hello未加载的时候,下面是可以运行的。

ClassPool cp = ClassPool.getDefault();

CtClass cc = cp.get("Hello");

Class c = cc.toClass();

//下面这种情况,由于Hello2已加载,所以会出错

Hello2 h=new Hello2();

CtClass cc2 = cp.get("Hello2");

Class c2 = cc.toClass();//这里会抛出java.lang.LinkageError 异常

//解决加载问题,可以指定一个未加载的ClassLoader

Class c3 = cc.toClass(new MyClassLoader());

6.1 使用javassist.Loader

从上面可以看到,如果在同一个ClassLoader加载两次Class抛出异常,为了方便javassist也提供一个Classloader供使用,例如

ClassPool pool = ClassPool.getDefault();

Loader cl = new Loader(pool);

CtClass ct = pool.get("test.Rectangle");

ct.setSuperclass(pool.get("test.Point"));

Class c = cl.loadClass("test.Rectangle");

Object rect = c.newInstance();

:

为了方便监听Javassist自带的ClassLoader的生命周期,javassist也提供了一个listener,可以监听ClassLoader的生命周期,例如:

//Translator 为监听器

public class MyTranslator implements Translator {

void start(ClassPool pool)

throws NotFoundException, CannotCompileException {}

void onLoad(ClassPool pool, String classname)

throws NotFoundException, CannotCompileException

{

CtClass cc = pool.get(classname);

cc.setModifiers(Modifier.PUBLIC);

}

}

//示例

public class Main2 {

public static void main(String[] args) throws Throwable {

Translator t = new MyTranslator();

ClassPool pool = ClassPool.getDefault();

Loader cl = new Loader();

cl.addTranslator(pool, t);

cl.run("MyApp", args);

}

}

//输出

% java Main2 arg1 arg2...

6.2 修改系统Class

由JVM规范可知,system classloader 是比其他classloader 是优先加载的,而system classloader 主要是加载系统Class,所以要修改系统Class,如果默认参数运行程序是不可能修改的。如果需要修改也有一些办法,即在运行时加入-Xbootclasspath/p: 参数的意义可以参考其他文件。下面修改String的例子如下:

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("java.lang.String");

CtField f = new CtField(CtClass.intType, "hiddenValue", cc);

f.setModifiers(Modifier.PUBLIC);

cc.addField(f);

cc.writeFile(".");

//运行脚本

% java -Xbootclasspath/p:. MyApp arg1 arg2...

6.3 动态重载Class

如果JVM运行时开启JPDA(Java Platform Debugger Architecture),则Class是运行被动态重新载入的。具体方式可以参考java.lang.Instrument。javassist也提供了一个运行期重载Class的方法,具体可以看API 中的javassist.tools.HotSwapper。

7、Introspection和定制

javassist封装了很多很方便的方法以供使用,大部分使用只需要用这些API即可,如果不能满足,Javassist也提供了一个低层的API(具体参考javassist.bytecode 包)来修改原始的Class。

7.1 插入source 文本在方法体前或者后

CtMethod 和CtConstructor 提供了 insertBefore()、insertAfter()和 addCatch()方法,它们可以插入一个souce文本到存在的方法的相应的位置。javassist 包含了一个简单的编译器解析这souce文本成二进制插入到相应的方法体里。

javassist 还支持插入一个代码段到指定的行数,前提是该行数需要在class 文件里含有。

插入的source 可以关联fields 和methods,也可以关联方法的参数。但是关联方法参数的时,需要在程序编译时加上 -g 选项(该选项可以把本地变量的声明保存在class 文件中,默认是不加这个参数的。)。因为默认一般不加这个参数,所以Javassist也提供了一些特殊的变量来代表方法参数:$1,$2,$args...要注意的是,插入的source文本中不能引用方法本地变量的声明,但是可以允许声明一个新的方法本地变量,除非在程序编译时加入-g选项。

方法的特殊变量说明:

$0, $1, $2, ...this and actual parameters
$argsAn array of parameters. The type of $args is Object[].
$$All actual parameters.For example, m($$) is equivalent to m($1,$2,...)
$cflow(...)cflow variable
$rThe result type. It is used in a cast expression.
$wThe wrapper type. It is used in a cast expression.
$_The resulting value
$sigAn array of java.lang.Class objects representing the formal parameter types
$typeA java.lang.Class object representing the formal result type.
$classA java.lang.Class object representing the class currently edited.

7.1.1 $0, $1, $2, ...

$0代码的是this,$1代表方法参数的第一个参数、$2代表方法参数的第二个参数,以此类推,$N代表是方法参数的第N个。例如:

//实际方法

void move(int dx, int dy)

//javassist

CtMethod m = cc.getDeclaredMethod("move");

//打印dx,和dy

m.insertBefore("{ System.out.println($1); System.out.println($2); }");

注意:如果javassist改变了$1的值,那实际参数值也会改变。

7.1.2 $args

$args 指的是方法所有参数的数组,类似Object[],如果参数中含有基本类型,则会转成其包装类型。需要注意的时候,$args[0]对应的是$1,而不是$0,$0!=$args[0],$0=this。

7.1.3 $$

$$是所有方法参数的简写,主要用在方法调用上。例如:

//原方法

move(String a,String b)

move($$) 相当于move($1,$2)

如果新增一个方法,方法含有move的所有参数,则可以这些写:

exMove($$, context) 相当于 exMove($1, $2, context)

7.1.4 $cflow

$cflow意思为控制流(control flow),是一个只读的变量,值为一个方法调用的深度。例如:

//原方法

int fact(int n) {

if (n <= 1)

return n;

else

return n * fact(n - 1);

}

//javassist调用

CtMethod cm = ...;

//这里代表使用了cflow

cm.useCflow("fact");

//这里用了cflow,说明当深度为0的时候,就是开始当第一次调用fact的方法的时候,打印方法的第一个参数

cm.insertBefore("if ($cflow(fact) == 0)"

+ "    System.out.println(\"fact \" + $1);");

7.1.5 $r

指的是方法返回值的类型,主要用在类型的转型上。例如:

Object result = ... ;

$_ = ($r)result;

如果返回值为基本类型的包装类型,则该值会自动转成基本类型,如返回值为Integer,则$r为int。如果返回值为void,则该值为null。

7.1.6 $w

$w代表一个包装类型。主要用在转型上。比如:Integer i = ($w)5; 如果该类型不是基本类型,则会忽略。

7.1.7 $_

$_代表的是方法的返回值。

7.1.8 $sig

$sig指的是方法参数的类型(Class)数组,数组的顺序为参数的顺序。

7.1.9 $class

$class 指的是this的类型(Class)。也就是$0的类型。

7.1.10 addCatch()

addCatch() 指的是在方法中加入try catch 块,需要主要的是,必须在插入的代码中,加入return 值。$e代表 异常值。比如:

CtMethod m = ...;

CtClass etype = ClassPool.getDefault().get("java.io.IOException");

m.addCatch("{ System.out.println($e); throw $e; }", etype);

实际代码如下:

try {

the original method body

}

catch (java.io.IOException e) {

System.out.println(e);

throw e;

}

8、修改方法体

CtMethod 和CtConstructor 提供了 setBody() 的方法,可以替换方法或者构造函数里的所有内容。

支持的变量有:

$0, $1, $2, ...this and actual parameters
$argsAn array of parameters. The type of $args is Object[].
$$All actual parameters.For example, m($$) is equivalent to m($1,$2,...)
$cflow(...)cflow variable
$rThe result type. It is used in a cast expression.
$wThe wrapper type. It is used in a cast expression.
$sigAn array of java.lang.Class objects representing the formal parameter types
$typeA java.lang.Class object representing the formal result type.
$classA java.lang.Class object representing the class currently edited.

注意 $_变量不支持。

8.1 替换方法中存在的source

javassist 允许修改方法里的其中一个表达式。 javassist.expr.ExprEditor 这个class 可以替换该表达式。例如:

CtMethod cm = ... ;

cm.instrument(

new ExprEditor() {

public void edit(MethodCall m)

throws CannotCompileException

{

if (m.getClassName().equals("Point")

&& m.getMethodName().equals("move"))

m.replace("{ $1 = 0; $_ = $proceed($$); }");

}

});

注意: that the substituted code is not an expression but a statement or a block. It cannot be or contain a try-catch statement.

方法instrument() 可以用来搜索方法体里的内容。比如调用一个方法,field访问,对象创建等。如果你想在某个表达式前后插入方法,则修改的souce如下:

{ before-statements;

$_ = $proceed($$);

after-statements; }

8.2 javassist.expr.MethodCall

MethodCall代表的是一个方法的调用。用replace()方法可以对调用的方法进行替换。

$0The target object of the method call.
This is not equivalent to this, which represents the caller-side this object.
$0 is null if the method is static.

$1, $2, ...

The parameters of the method call.
$_The resulting value of the method call.
$rThe result type of the method call.
$classA java.lang.Class object representing the class declaring the method.
$sigAn array of java.lang.Class objects representing the formal parameter types
$typeA java.lang.Class object representing the formal result type.
$proceedThe name of the method originally called in the expression.

注意:$w, $args 和 $$也是允许的。$0不是this,是只调用方法的Object。$proceed指的是一个特殊的语法,而不是一个String。

8.3 javassist.expr.ConstructorCall

ConstructorCall 指的是一个构造函数,比如:this()、super()的调用。ConstructorCall.replace()是用来用替换一个块当调用构造方法的时候。

$0The target object of the constructor call. This is equivalent to this.
$1, $2, ...The parameters of the constructor call.
$classA java.lang.Class object representing the class declaring the constructor.
$sigAn array of java.lang.Class objects representing the formal parameter types.
$proceedThe name of the constructor originally called in the expression.

$w, $args 和 $$  也是允许的。

8.4 javassist.expr.FieldAccess

FieldAccess代表的是Field的访问类。

$0The object containing the field accessed by the expression. This is not equivalent to this.
this represents the object that the method including the expression is invoked on.
$0 is null if the field is static.

$1

The value that would be stored in the field if the expression is write access.
Otherwise, $1 is not available.
$_The resulting value of the field access if the expression is read access.
Otherwise, the value stored in $_ is discarded.
$rThe type of the field if the expression is read access.
Otherwise, $r is void.
$classA java.lang.Class object representing the class declaring the field.

$type

A java.lang.Class object representing the field type.
$proceedThe name of a virtual method executing the original field access. .

$w, $args 和 $$  也是允许的。

8.5 javassist.expr.NewExpr

NewExpr代表的是一个Object 的操作(但不包括数组的创建)。

$0null

$1, $2, ...

The parameters to the constructor.
$_The resulting value of the object creation.
A newly created object must be stored in this variable.
$rThe type of the created object.
$sigAn array of java.lang.Class objects representing the formal parameter types
$typeA java.lang.Class object representing the class of the created object.
$proceedThe name of a virtual method executing the original object creation. .

$w, $args 和 $$  也是允许的。

8.6 javassist.expr.NewArray

NewArray 代表的是数组的创建。

$0null

$1, $2, ...

The size of each dimension.
$_The resulting value of the object creation. 
A newly created array must be stored in this variable.
$rThe type of the created object.
$typeA java.lang.Class object representing the class of the created array .
$proceedThe name of a virtual method executing the original array creation. .

$w, $args 和 $$  也是允许的。

例如:

String[][] s = new String[3][4];

$1 和 $2 的值为 3 和 4, $3 得不到的.

String[][] s = new String[3][];

$1 的值是 3 ,但 $2 得不到的.

8.7 javassist.expr.Instanceof

Instanceof 代表的是Instanceof 表达式。

$0null

$1

The value on the left hand side of the original instanceof operator.
$_The resulting value of the expression. The type of $_ is boolean.
$rThe type on the right hand side of the instanceof operator.
$typeA java.lang.Class object representing the type on the right hand side of the instanceof operator.
$proceedThe name of a virtual method executing the original instanceof expression.
It takes one parameter (the type is java.lang.Object) and returns true
if the parameter value is an instance of the type on the right hand side of
the original instanceof operator. Otherwise, it returns false.

$w, $args 和 $$  也是允许的。

8.8 javassist.expr.Cast

Cast 代表的是一个转型表达式。

$0null

$1

The value the type of which is explicitly cast.
$_The resulting value of the expression. The type of $_ is the same as the type
after the explicit casting, that is, the type surrounded by ( ).
$rthe type after the explicit casting, or the type surrounded by ( ).
$typeA java.lang.Class object representing the same type as $r.
$proceedThe name of a virtual method executing the original type casting.
It takes one parameter of the type java.lang.Object and returns it after
the explicit type casting specified by the original expression.

$w, $args 和 $$  也是允许的。

8.9 javassist.expr.Handler

Handler 代表的是一个try catch 声明。

$1The exception object caught by the catch clause.

$r

the type of the exception caught by the catch clause. It is used in a cast expression.
$wThe wrapper type. It is used in a cast expression.
$typeA java.lang.Class object representing
the type of the exception caught by the catch clause.

9 新增一个方法或者field

Javassist 允许开发者创建一个新的方法或者构造方法。新增一个方法,例如:

CtClass point = ClassPool.getDefault().get("Point");

CtMethod m = CtNewMethod.make(

"public int xmove(int dx) { x += dx; }",

point);

point.addMethod(m);

在方法中调用其他方法,例如:

CtClass point = ClassPool.getDefault().get("Point");

CtMethod m = CtNewMethod.make(

"public int ymove(int dy) { $proceed(0, dy); }",

point, "this", "move");

其效果如下:

public int ymove(int dy) { this.move(0, dy); }

下面是javassist提供另一种新增一个方法(未看明白):

Javassist provides another way to add a new method. You can first create an abstract method and later give it a method body:

CtClass cc = ... ;

CtMethod m = new CtMethod(CtClass.intType, "move",

new CtClass[] { CtClass.intType }, cc);

cc.addMethod(m);

m.setBody("{ x += $1; }");

cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);

Since Javassist makes a class abstract if an abstract method is added to the class, you have to explicitly change the class back to a non-abstract one after calling setBody().

9.1 递归方法

CtClass cc = ... ;

CtMethod m = CtNewMethod.make("public abstract int m(int i);", cc);

CtMethod n = CtNewMethod.make("public abstract int n(int i);", cc);

cc.addMethod(m);

cc.addMethod(n);

m.setBody("{ return ($1 <= 0) ? 1 : (n($1 - 1) * $1); }");

n.setBody("{ return m($1); }");

cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);

9.2 新增field

如下:

CtClass point = ClassPool.getDefault().get("Point");

CtField f = new CtField(CtClass.intType, "z", point);

point.addField(f);

//point.addField(f, "0");    // initial value is 0.

或者:

CtClass point = ClassPool.getDefault().get("Point");

CtField f = CtField.make("public int z = 0;", point);

point.addField(f);

9.3 移除方法或者field

调用removeField()或者removeMethod()。

10 注解

获取注解信息:

//注解

public @interface Author {

String name();

int year();

}

//javassist代码

CtClass cc = ClassPool.getDefault().get("Point");

Object[] all = cc.getAnnotations();

Author a = (Author)all[0];

String name = a.name();

int year = a.year();

System.out.println("name: " + name + ", year: " + year);

11  javassist.runtime 

12 import

引用包:

ClassPool pool = ClassPool.getDefault();

pool.importPackage("java.awt");

CtClass cc = pool.makeClass("Test");

CtField f = CtField.make("public Point p;", cc);

cc.addField(f);

13 限制

(1)不支持java5.0的新增语法。不支持注解修改,但可以通过底层的javassist类来解决,具体参考:javassist.bytecode.annotation

(2)不支持数组的初始化,如String[]{"1","2"},除非只有数组的容量为1

(3)不支持内部类和匿名类

(4)不支持continue和btreak 表达式。

(5)对于继承关系,有些不支持。例如

class A {}

class B extends A {}

class C extends B {}

class X {

void foo(A a) { .. }

void foo(B b) { .. }

}

如果调用  x.foo(new C()),可能会调用foo(A) 。

(6)推荐开发者用#分隔一个class name和static method或者 static field。例如:

javassist.CtClass.intType.getName()推荐用javassist.CtClass#intType.getName()

13 底层API

14 debug

可以设置一个文件夹,javassist生成的class会保存在该文件夹下面。例如:CtClass.debugDump = "./dump"; 默认debugDump=null.

转载于:https://my.oschina.net/junwuwei/blog/876085

相关文章:

金融领域首个开源中文BERT预训练模型,熵简科技推出FinBERT 1.0

出品 | AI科技大本营头图 | CSDN付费下载于东方IC为了促进自然语言处理技术在金融科技领域的应用和发展&#xff0c;熵简科技 AI Lab 近期开源了基于 BERT 架构的金融领域预训练语言模型 FinBERT 1.0。据悉&#xff0c;这是国内首个在金融领域大规模语料上训练的开源中文BERT预…

raspberry pi下使用mp3blaster播放mp3音乐

首先&#xff1a;sudo apt-get install mp3blaster mp3blaster wode.mp3会报错 但是加padsp mp3blaster wode.mp3 就可以正常播放了

把Excel文件中的数据读入到DataGrid中

作者Blog&#xff1a;http://blog.csdn.net/net_lover/使用Excel文件做为DataGrid的数据源是非常简单的&#xff0c;一旦数据被装载进来&#xff0c;就可以把数据再保存进SQL Server或XML中。我们只需要简单地使用OLE DB Provider 来访问Excel文件&#xff0c;然后返回DataSet即…

Vue 数组中更新属性值后,视图不更新,等待其他元素更新后会触发的解决办法...

因为 JavaScript 的限制&#xff0c;Vue.js 不能检测到下面数组变化&#xff1a; 直接用索引设置元素&#xff0c;如 vm.items[0] {}&#xff1b; 修改数据的长度&#xff0c;如 vm.items.length 0。 this.examineIntro.questionList[0].selList[1].url url;为了解决问题 (…

DeepMind 最新论文解读:首次提出离散概率树中的因果推理算法

翻译 | 高卫华出品 | AI科技大本营头图 | CSDN付费下载自视觉中国当前&#xff0c;一些前沿AI研究人员正在寻找用于表示上下文特定的因果依赖关系清晰的语义模型&#xff0c;这是因果归纳所必需的&#xff0c;在 DeepMind的算法中可看到这种概率树模型。概率树图用于表示概率空…

使用c#+(datagrid控件)编辑xml文件

作者Blog&#xff1a;http://blog.csdn.net/ouyang76cn/ 使用c#(datagrid控件)编辑xml文件 这个源码是我根据网上一个vb.net编辑xml文件的原理用c#重写的。除重用xml文件外.并未重用任何代码&#xff01;. 这小段代码&#xff0c;可对xml文件的记录进行删除&#xff0c;修改&am…

HorizontalTable

2019独角兽企业重金招聘Python工程师标准>>> HorizontalTable 实现了可水平滚动的 TableView。 转载:http://www.adobex.com/ios/source/details/00000761.htm 转载于:https://my.oschina.net/u/868244/blog/106055

敏捷软件开发的12个原则

作为一个软件工程师&#xff0c;软件设计和开发是最重要的技能&#xff0c;但是&#xff0c;从整个产品的角度上讲&#xff0c;项目管理能力比开发能力更重要&#xff0c;本文摘自Robert大叔的《敏捷软件开发》&#xff0c;粗体是Robert大叔的话&#xff0c;细体是我的理解。 1…

JAVE EE 企业级开发之从零开始学JAVA【51CTO技术论坛】

http://bbs.51cto.com JAVE EE 企业级开发之从零开始学JAVA 从零开始学JAVA&#xff1f;YES!本刊内容全部为午饭redking整理、撰写&#xff0c;所涉及内容均为原创&#xff0c;非常适合入门级JAVA新人学习&#xff0c;从理论到实际&#xff0c;跟随redking一起学习JAVA&#x…

打工人,打工魂,抽终身会员,成为人上人!

今年双11&#xff0c;CSDN直接来了个前所未有的福利大奖&#xff01;CSDN终身会员还有全站课程免费学&#xff01;喜欢吗&#xff1f;哈哈哈哈&#xff0c;还没完呢&#xff01;买CSDN年会员&#xff0c;不要&#xffe5;299&#xff0c;只要&#xffe5;199&#xff01;超级年…

如何创建一个用弹出窗口来查看详细信息的超链接列

如何创建一个用弹出窗口来查看详细信息的超链接列出处&#xff1a;www.dotnetjunkie.com 这篇文章来自于一位忠实的DotNetJunkie的建议&#xff0c;他最初发了一封email给我们&#xff0c;要求我们给出一个例子来说明如何在DataGrid中设置一个当用户点击时能够弹出显示其…

HashSet的使用

2019独角兽企业重金招聘Python工程师标准>>> 1.Set中元素是无序的 HashSet setnew HashSet(); set.add("a"); set.add("b"); set.add("c"); set.add("d"); System.out.println(set);//结果&#xff1a;[d,b,c,a]2.Set不允许…

python实现nginx图形界面管理

好久没有更新博客了&#xff0c;最近一直在学习python&#xff0c;于是&#xff0c;在有空闲的时间写下python视图界面管理nginx&#xff0c;写得不够好&#xff0c;不过希望能帮忙到其他童鞋&#xff0c;再次感叹&#xff0c;强大的python,不说了&#xff0c;上代码。 [rootlo…

小马智行获2.67亿美元新融资,估值超53亿美元

11月6日&#xff0c;小马智行&#xff08;Pony.ai&#xff09;宣布获得由加拿大安大略省教师退休基金会&#xff08;Ontario Teachers Pension Plan&#xff0c;OTPP&#xff09;旗下教师创新平台&#xff08;Teachers’ Innovation Platform, TIP&#xff09;领投总计2.67亿美…

DataSet导出CSV格式(ASP.NET,C#)

DataSet导出CSV格式(ASP.NET,C#)作者&#xff1a;NotMSN:notkinghotmail.comEmail:notssohu.com本文引用下面的 Microsoft .NET 框架类库命名空间&#xff1a;System.Data;System.Web.UI.WebControls;概要本文解决将DataSet导出到CSV格式问题、将DataGrid中的数据导出到CSV格式…

ArcEngine的ToolbarControl解析

转自Love Lyre原文 ArcEngine的ToolbarControl解析 ToolbarControlClass有三个主要的接口: IToolbarControl, IToolbarControl2, IToolbarControlDefault 其中,IToolbarControl2是IToolbarControl的新版本.而IToolbarControlDefault is a pure dispatch interface,始终是I…

在C#里实现DATAGRID的打印预览和打印

作者Blog&#xff1a;http://blog.csdn.net/qieyj/很多人都在论坛里问&#xff0c;如何实现DATAGRID的打印预览和打印&#xff0c;现在我就把这方面的源代码告诉大家。这段代码也花费了我1个晚上的时间&#xff0c;呵呵&#xff01;数据库是基于sql server2000自带的northwind。…

ORACLE SQL: 经典查询练手第二篇

本文使用的实例表结构与表的数据如下&#xff1a; scott.emp员工表结构如下&#xff1a; SQL> DESC SCOTT.EMP;Name Type Nullable Default Comments -------- ------------ -------- ------- -------- EMPNO NUMBER(4) 员工编号 ENAME…

第十三届光华工程科技奖名单揭晓!这40位专家和1个团体获奖

11月8日&#xff0c;第十三届光华工程科技奖揭晓仪式在北京隆重举行。工程科技是推动人类进步的发动机&#xff0c;是产业革命、经济发展、社会进步的有力杠杆。光华工程科技奖由中国工程院主管&#xff0c;目前已是第十三届&#xff0c;被誉为“中国工程界最高奖项”&#xff…

【C#公共帮助类】给大家分享一些加密算法 (DES、HashCode、RSA、AES等)

http://www.cnblogs.com/yuangang/p/5466068.html转载于:https://www.cnblogs.com/daming1233/p/6704562.html

MongoDB的备份(mongodump)与恢复(mongorestore)

为什么80%的码农都做不了架构师&#xff1f;>>> 不用多想&#xff0c;数据的备份无论什么时候都是必须的&#xff0c;尤其是重要数据。 MongoDB也提供了备份和恢复的功能&#xff0c;分别是MongoDB下载目录下的mongdump.exe和mongorestore.exe文件。 先介绍下命令…

Windows 2000/XP 注册表终极修改(转载)

Microsoft Windows 2000/XP 是一个强大的操作系统&#xff0c;为我们提供了以往Windows 9x从未有过的安全性能&#xff0c;可是你是否感觉某些地方的设置还不够呢&#xff0c;这里就对Windows 2000 的注册表进行一些修改来达到我们的目的。 一、修改开始菜单和任务栏 由于以往不…

百度CTO王海峰获“光华工程科技奖”,深耕自然语言处理近30年

11月8日&#xff0c;第十三届光华工程科技奖揭晓仪式在北京举行。该奖项被誉为“中国工程界最高奖项”&#xff0c;旨在对我国工程科技及管理领域做出杰出贡献的科学家、工程师进行表彰。百度CTO王海峰因其在人工智能领域、尤其是自然语言处理领域的卓越贡献&#xff0c;成为AI…

python自定义库文件路径

各有各的小烦恼&#xff0c;各有的小期待 这是人家私事&#xff0c;不要大嘴巴 在Pycharm中import whois时&#xff0c;总是失败 原因是安装了python3.x相关操作过程&#xff0c;将环境变量path中关于Python的配置c:\Python27和c:\Python27\Scripts都删除&#xff0c;pycharm中…

开机BIOS语言(转载)

开机自检时出现问题后会出现各种各样的英文短句&#xff0c;短句中包含了非常重要的信息&#xff0c;读懂这些信息可以自己解决一些小问题&#xff0c;可是这些英文难倒了一部分朋友&#xff0c;下面是一些常见的BIOS短句的解释&#xff0c;大家可以参考一下。 1.CMOS battery …

参与开源项目,结识技术大牛!CSDN“开源加速器计划”招募志愿者啦!

什么是“CSDN开源加速器计划”&#xff1f;纵观近 30 年的科技创新&#xff0c;开源已成为全球技术应用和行业数字化发展的基石&#xff0c;尤其最近几年&#xff0c;开源的商业化得到了极大突破&#xff0c;开源正在成为全球科技的强劲驱动力。在开源生态中&#xff0c;开发者…

破解CentOS的root密码(救援模式无密码)

开机后&#xff0c;在倒数读秒的时候按任意键、跳转画面后&#xff0c;再按E键&#xff0c;进入如下界面&#xff1a; 此时把光标定位到第二行&#xff0c;再按E键&#xff08;意为&#xff1a;在启动顺序里编辑这条命令&#xff09;&#xff0c;如下图&#xff0c;此时输入“空…

第九—十三单元练习

<<<第九单元练习>>>1.在desktop主机中建立用户westos&#xff0c;并设定其密码为westoslinux2.配置desktop中的sshd服务要求如下&#xff1a;*&#xff09;设定sshd服务只允许westos用户可以被访问使用*&#xff09;创建westos用户的key认证方式*&#xff09…

用 Java 训练深度学习模型,原来这么简单

作者 | DJL-Keerthan&Lanking来源 | HelloGitHub头图 | CSDN下载自东方IC前言很长时间以来&#xff0c;Java 都是一个很受企业欢迎的编程语言。得益于丰富的生态以及完善维护的包和框架&#xff0c;Java 拥有着庞大的开发者社区。尽管深度学习应用的不断演进和落地&#xf…

重装操作系统的20条原则(转载)

系统是否需重装&#xff0c;三条法则帮你忙&#xff1a; 如果系统出现以下三种情况之一&#xff0c;应该是你考虑重装系统的时候了&#xff1a;   1)系统运行效率变得低下&#xff0c;垃圾文件充斥硬盘且散乱分布又不便于集中清理和自动清理&#xff1b;   2)系统频繁出错&…