2009年12月23日

[ -a FILE ] 如果 FILE 存在则为真。
[ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。
[ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。
[ -d FILE ] 如果 FILE 存在且是一个目录则为真。
[ -e FILE ] 如果 FILE 存在则为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。
[ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。
[ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。
[ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。
[ -r FILE ] 如果 FILE 存在且是可读的则为真。
[ -s FILE ] 如果 FILE 存在且大小不为0则为真。
[ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。
[ -w FILE ] 如果 FILE 如果 FILE 存在且是可写的则为真。
[ -x FILE ] 如果 FILE 存在且是可执行的则为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。
[ -G FILE ] 如果 FILE 存在且属有效用户组则为真。
[ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则为真。
[ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1FILE2 does not则为真。 exists and
[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。
[ -o OPTIONNAME ] 如果 shell选项 “OPTIONNAME” 开启则为真。
[ -z STRING ] “STRING” 的长度为零则为真。
[ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。
[ STRING1 == STRING2 ] 如果2个字符串相同。 “=” may be used instead of “==” for strict POSIX compliance则为真。
[ STRING1 != STRING2 ] 如果字符串不相等则为真。
[ STRING1 < STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale则为真。
[ STRING1 > STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale则为真。
[ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.

posted @ 2011-09-27 16:23 xsong 阅读(1300) | 评论 (0)编辑 收藏

     摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->//源代码class TT{       static int tt = 5;&nb...  阅读全文

posted @ 2011-09-23 13:55 xsong 阅读(336) | 评论 (0)编辑 收藏

#include <stdio.h>

int main(int argc, char **argv) {

    
/**
     * sizeof  关键字
     
*/
    
int i=0;
    printf(
"sizeof int %lu \n",sizeof(i)); // 4

    
int *p=NULL;
    printf(
"sizeof point %lu \n" ,sizeof(p) )    ; // 8
    printf("sizeof *p %lu \n",sizeof *p); // 4

    
int a[100];
    printf(
"sizeof array %lu \n"sizeof(a));// 100*4
    printf("sizeof a[100] %lu \n",sizeof(a[100])); // 4
    printf("sizeof &a %lu \n"sizeof(&a)); // 8  &a 是指针

    
return 0;
}

posted @ 2011-09-16 15:04 xsong 阅读(219) | 评论 (0)编辑 收藏

#include <stdio.h>
#include 
<stdlib.h>
#include 
<event.h>
#include 
<evhttp.h>

void generic_request_handler(struct evhttp_request *req, void *arg) {

    
struct evbuffer *return_buffer=evbuffer_new();

    evbuffer_add_printf(return_buffer,
"welcome");
    evhttp_send_reply(req,HTTP_OK,
"Client",return_buffer    );
    evbuffer_free(return_buffer);
}

int main(int argc, char **argv) {
    
short http_port =8082;
    
char *http_addr="127.0.0.1";
    
struct evhttp *http_serv=NULL;
    event_init();

    http_serv
= evhttp_start(http_addr,http_port);
    evhttp_set_gencb(http_serv,generic_request_handler,NULL);
    event_dispatch();
    
return 0;
}

posted @ 2011-08-05 14:51 xsong 阅读(1345) | 评论 (0)编辑 收藏

enum Action {Start, Stop, Rewind, Forward};

// Special type of class 
enum Status {
  Flunk(
50), Pass(70), Excel(90);
  
private final int value;
  Status(
int value) { this.value = value; }
  
public int value() { return value; } 
};

Action a 
= Action.Stop;
if (a != Action.Start)
  System.out.println(a);               
// Prints "Stop"

Status s 
= Status.Pass;
System.out.println(s.value());      
// Prints "70"

posted @ 2011-08-01 16:20 xsong 阅读(211) | 评论 (0)编辑 收藏

posted @ 2011-07-04 15:44 xsong 阅读(286) | 评论 (0)编辑 收藏

安装  编辑 ~/.vimrc

syntax on
set tabstop=4
set softtabstop=4
set shiftwidth=4
set autoindent
set cindent
set nu

if &term=="xterm"
  set t_Co=8
  set t_Sb=^[[4%dm
  set t_Sf=^[[3%dm
endif

let g:neocomplcache_enable_at_startup = 1 


"括号补全功能,

:inoremap ( ()<ESC>i
        :inoremap ) <c-r>=ClosePair(')')<CR>
:inoremap { {}<ESC>i
    :inoremap } <c-r>=ClosePair('}')<CR>
    :inoremap [ []<ESC>i
    :inoremap ] <c-r>=ClosePair(']')<CR>
    :inoremap < <><ESC>i
    :inoremap > <c-r>=ClosePair('>')<CR>

    function ClosePair(char)
    if getline('.')[col('.') - 1] == a:char
    return "\<Right>"
    else
    return a:char
    endif
    endf

posted @ 2011-06-11 12:58 xsong 阅读(728) | 评论 (0)编辑 收藏

    c 提供了 atoi atof 等函数实现了字符串转化数值的函数。使用方法简单。
但是如果转化 "123ss"等字符串里包含非数值的字符串时,则会自动转化为 123,不会抛出异常。
想要验证 字符串是否是数值格式  可使用
strtol (__const char *__restrict __nptr, char **__restrict __endptr, int __base)
 nptr指向的字符串, 
strtol()函数检测到第一个非法字符时,立即停止检测,其后的所有字符都会被当作非法字符处理。合法字符串会被转换为long int, 作为函数的返回值。非法字符串,即从第一个非法字符的地址,被赋给*endptr**endptr是个双重指针,即指针的指针。strtol()函数就是通过它改变*endptr的值,即把第一个非法字符的地址传给endptr

    char *str1="1231",*endptr1;
    
char *str2="123sss",*endptr2;

    printf(
"atoi str2 is %i\n",atoi(str1));
    
int i,j;//atoi(str);
    i=strtol(str1,&endptr1,10);
    
if(*endptr1!=NULL){
        printf(
"endptr1 is %s\n",endptr1);
    }
    printf(
"str1 auto int %i\n",i);
    j
=strtol(str2,&endptr2,10);
    
if(*endptr2!=NULL){
        printf(
"endptr2 is %s\n",endptr2);
    }
    printf(
"str2 auto long int %i\n",j);

posted @ 2011-05-30 15:13 xsong 阅读(588) | 评论 (0)编辑 收藏

系统中的浏览器都是由在/usr/bin中的与浏览器同名的脚本文件启动的.你可以对其进行编辑加入环境变量进行连接库文件进行预载.对firefox浏览器,用sudo权限编辑/usr/bin/firefox,将
export LD_PRELOAD=/usr/lib/libc/memcpy-preload.so(不行就改为export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libc/memcpy-preload.so)加入文件的第一行就可以了

posted @ 2011-05-26 13:37 xsong 阅读(471) | 评论 (0)编辑 收藏

/*
 ============================================================================
 Name        : test.c
 Author      : xsong
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 
*/

#include 
<stdio.h>
#include 
<stdlib.h>
#include
<string.h>

int main(void) {

    
char buffer[] = "buffer example";
    
//  memset 填充字符串
    printf("buffer size %i \n"sizeof(buffer));
    printf(
"before memsetd -> %s \n", buffer);
    
int mpoint = memset(buffer, '*'sizeof(buffer));
    printf(
"memset return point -> %i \n", mpoint);
    printf(
"after memsetd -> %s \n", buffer);
    
//strlen 取得字符串长度
    int buffer_length = strlen(buffer);
    printf(
"buffer size -> %i \n", buffer_length);
    
//字符串连接
    char d[10= "foo";
    
char s[10= "bar";
    strcat(d, s);
    printf(
"%s %s\n", d, s);

    
//字符串分割
    char str[] = "root:x::0:root:/root:/bin/bash:";
    
char *token;
    token 
= strtok(str, ":");

    
do {
        printf(
"%s \n", token);
    } 
while ((token = strtok(NULL, ":")) != NULL);

    
return EXIT_SUCCESS;
}

posted @ 2011-05-18 15:38 xsong 阅读(259) | 评论 (0)编辑 收藏

#include <stdio.h>
#include 
<stdlib.h>
#include
<string.h>

typedef 
struct{
    
int number;
    
char *msg;
} unit_t;

int main(void) {
    
// 使用 malloc 分配内存, 使用free释放内存,并设置为NULL 杜绝野指针
    unit_t *p=malloc(sizeof(unit_t));
    p
->number=10;
    p
->msg=malloc(10);
    strcpy(p
->msg,"hello");
    printf(
"number is %i \n",p->number);
    printf(
"msg is %s \n",p->msg);
    
//如果先free(p),p成了野指针,就不能再通过p->msg访问内存
    free(p->msg);
    free(p);
    
//如果 free(p)  两次, 则会引发系统错误,
    p=NULL;

    
if(p==NULL){
        printf(
"p point is empty");
        exit(
-1);
    }

    
return EXIT_SUCCESS;
}

posted @ 2011-05-16 13:42 xsong 阅读(170) | 评论 (0)编辑 收藏

/*数组和指针
* 在函数原型中,如果参数是数组,则等价于参数是指针的形式,例如:
void func(int a[10])
{

}
等价于:

void func(int *a)
{

}
第一种形式方括号中的数字可以不写,仍然是等价的:

void func(int a[])
{

}
*/

int a[]={5,6,7,8};
// int *p=&a[0]; 一般简写为
int
 *p=a;
printf(
"p address %p \n",p);
printf(
"p value %i \n"*p);
//指针自加 p++  p=a[1]
p++;
printf(
"p++ value %i \n",*p);

// 指针的比较运算,比较的是两个指针的地址, 但只有一个数组内的指针比较才有意义。
//如果为true  输出 1, 如果为 false 输出0  ,c 语言中没有 boolean 类型
printf(" complete p %i \n", p+2>p);
printf(
" complete p %i \n", p+2<p);
//指针相减表示两个指针之间相差的元素个数, C语言也规定两个指针不能相加
printf(" p-1 value %i",*(p-1));

posted @ 2011-05-13 11:57 xsong 阅读(171) | 评论 (0)编辑 收藏

//使用指针访问结构体

struct unit{
char c;
int num;
};

 
struct unit u;
struct unit *p=&u;
//可使用 (*p).c=‘a'  通过指针访问结构体里的数据, c提供了 ->运算符 简化指针对结构体的访问 p->c='c'
(*p).c='a';
(
*p).num=2;
p
->c='c';
p
->num=1;

printf(
"p->c is %c \n",p->c);
printf(
"p->i is %i \n",p->num);

posted @ 2011-05-13 11:57 xsong 阅读(191) | 评论 (0)编辑 收藏

结构体
    *


struct Complex{ 
     
double x,y;
} z1;

//或者
struct Complex{
     
double x,y;
};
struct Complex z1;


//声明时初始化
struct Stu{
char name;
}s1
={'s'};

//先声明,后初始化
struct Stu{
     
char name;
};
struct Stu s1={s};

//结构体赋值 ,copy s1的内容给s2

struct Stu s2=s1;
s2.name
='m'

printf(
"s1.name %c",s1.name); // print s
printf("s2.name %c",s2.name); //print m

//结构体嵌套
struct dog{
char run;
};
struct cat{
char run;
};
struct animal{
struct dog dd;
struct cat cc;
};


 
//嵌套的结构体分别初始化
struct dog dd={'d'};
struct cat cc={'c'};
struct animal a1={dd ,cc};
printf(
"dog-dd run is %c \n",a1.dd.run);
printf(
"cat-cc run is %c",a1.cc.run);



posted @ 2011-05-13 11:55 xsong 阅读(199) | 评论 (0)编辑 收藏

声明一个字符串,其实也就是一个char的数组
char str[20] = "Hello, world";
printf("str is %s",str);
如果定义数组的大小 小于字符串字面值“Hello ,world"; 则编译器会发出警告信息。所以最好定义不定长度的数组
char str[ ]="hello, world";

posted @ 2011-05-13 11:55 xsong 阅读(151) | 评论 (0)编辑 收藏

deb http://mirrors.163.com/debian/ testing main non-free contrib
deb-src http://mirrors.163.com/debian/ testing main non-free contrib

deb http://mirrors.163.com/debian-security testing/updates main
deb-src http://mirrors.163.com/debian-security testing/updates main

posted @ 2011-05-13 11:52 xsong 阅读(2132) | 评论 (0)编辑 收藏

     摘要: java 证书公钥加密 生成xml 使用http post发送到servl et , servlet私钥解密 xml格式 1 :消息格式: XML 消息格式如下: <?xml version="1.0" encoding="UTF-8"> <Requ...  阅读全文

posted @ 2011-05-13 11:50 xsong 阅读(1687) | 评论 (0)编辑 收藏

1.OutputStream写入String

ByteArrayOutputStream baos 
= new ByteArrayOutputStream();  
//向OutPutStream中写入,如 message.writeTo(baos);  
String str = baos.toString();  

2.字符串转inputStream

String string;  
//  
InputStream is = new ByteArrayInputStream(string.getBytes());

3.InputStream转字符串

ByteArrayOutputStream baos 
= new ByteArrayOutputStream();  
int i;  
while ((i = is.read()) != -1) {  
    baos.write(i);  
}  
String str 
= baos.toString();  
System.out.println(str);  


4.String写入OutputStream

OutputStream os 
= System.out;  
os.write(string.getBytes());

posted @ 2011-05-13 11:48 xsong 阅读(4912) | 评论 (0)编辑 收藏

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

/**
 * User: fengxuesong
 * Date: 11-3-30
 * Time: 下午4:48
 * 使用 DES 加密解密
 
*/
public class DesTest {

    
static final byte[] IV = new byte[]{-29105540-94-98-113-100};
    
static final String priKey="11111111111";
    
static final String data="admin11";

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

        
//加密
        String encrypt  = encodeDesWithBase64(priKey,data);
        
//输出加密的字符串
        System.out.println(encrypt );

        String decrypt 
=decodeDesWithBase64(priKey,encrypt );
        System.out.println(decrypt );
    }

    
private static String encodeDesWithBase64(String priKey,String data) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        DESKeySpec desKS 
= new DESKeySpec(priKey.getBytes());
        SecretKeyFactory skf 
= SecretKeyFactory.getInstance("DES");
        SecretKey sk 
= skf.generateSecret(desKS);
        Cipher cip 
= Cipher.getInstance("DES/CBC/PKCS5Padding");
        cip.init(Cipher.ENCRYPT_MODE, sk, 
new IvParameterSpec(IV));
        
byte bb [] =cip.doFinal(data.getBytes());
        
return new BASE64Encoder().encode(bb);
    }
    
private static String decodeDesWithBase64(String priKey,String data) throws Exception{
        DESKeySpec desKS 
= new DESKeySpec(priKey.getBytes());
        SecretKeyFactory skf 
= SecretKeyFactory.getInstance("DES");
        SecretKey sk 
= skf.generateSecret(desKS);
        Cipher cip 
= Cipher.getInstance("DES/CBC/PKCS5Padding");
        cip.init(Cipher.DECRYPT_MODE, sk, 
new IvParameterSpec(IV));
        
byte bb [] =cip.doFinal(new BASE64Decoder().decodeBuffer(data));
        
return new String(bb);
    }
}

posted @ 2011-05-13 11:46 xsong 阅读(266) | 评论 (0)编辑 收藏

Tomcat Server在启动的时候将构造一个ClassLoader树,以保证模块的类库是私有的
Tomcat Server的ClassLoader结构如下:

其中:
- Bootstrap - 载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar
- System - 载入$CLASSPATH/*.class
- Common - 载入$CATALINA_HOME/common/...,它们对TOMCAT和所有的WEB APP都可见
- Catalina - 载入$CATALINA_HOME/server/...,它们仅对TOMCAT可见,对所有的WEB APP都不可见
- Shared - 载入$CATALINA_HOME/shared/...,它们仅对所有WEB APP可见,对TOMCAT不可见(也不必见)
- WebApp? - 载入ContextBase?/WEB-INF/...,它们仅对该WEB APP可见

posted @ 2011-05-13 11:44 xsong 阅读(180) | 评论 (0)编辑 收藏

假设来自客户的请求为:
http://localhost:8080/wsota/wsota_index.jsp

1) 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
2) Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
3) Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host
4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
5) localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context
6) Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)
7) path="/wsota"的Context获得请求/wsota_index.jsp,在它的mapping table中寻找对应的servlet
8) Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
10)Context把执行完了之后的HttpServletResponse对象返回给Host
11)Host把HttpServletResponse对象返回给Engine
12)Engine把HttpServletResponse对象返回给Connector
13)Connector把HttpServletResponse对象返回给客户browser

posted @ 2011-05-13 11:44 xsong 阅读(161) | 评论 (0)编辑 收藏

Bootstrap 的 init 方法中 通过反射动态调用 Catalina.start() 
Catalina 类 负责开始或者停止服务
 Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
 Object startupInstance 
= startupClass.newInstance();
Catalina 完成了3个任务 
  •  处理xml文件, load 方法中使用 Digester 处理server.xml文件,转化为java对象
if (getServer() == null) {
            load();
        }
  •     实例化一个server  

 getServer().start();
  •      给jvm 注册一个关闭 的Hook(钩子)
Runtime.getRuntime().addShutdownHook(shutdownHook);
  • 线程等待
 await();  调用 StandardServer 的 await()   StandardServer 处理 Server相关的操作,
     /**
     * Wait until a proper shutdown command is received, then return.
     * This keeps the main thread alive - the thread pool listening for http
     * connections is daemon threads.
     */
     StandardServer.await() 处理 当前的主线程,即 启动 tomcat 的主线程

    
try {
        awaitSocket 
= new ServerSocket(port, 1,
                InetAddress.getByName(address));
    }

    
catch( IOException e ) {
        log.error(
"StandardServer.await: create[" + address + ":" + port + "]: ", e);
        
return;
    }

    
try {
        awaitThread 
= Thread.currentThread();

// Loop waiting for a connection and a valid command
        while (!stopAwait) {
            ServerSocket serverSocket 
= awaitSocket;

            
if (serverSocket == null) {
                
break;
            }
// Wait for the next connection
            Socket socket = null;
            StringBuilder command 
= new StringBuilder();
            
try {
                InputStream stream;
                
try {
                    socket 
= serverSocket.accept();
                    socket.setSoTimeout(
10 * 1000);  // Ten seconds
                    stream = socket.getInputStream();
                } 
catch (AccessControlException ace) {
                    log.warn(
"StandardServer.accept security exception: " + ace.getMessage(), ace);
                    
continue;
                } 
catch (IOException e) {
                    
if (stopAwait) {
// Wait was aborted with socket.close()
                        break;
                    }
                    log.error(
"StandardServer.await: accept: ", e);
                    
break;
                }
// Read a set of characters from the socket
                int expected = 1024// Cut off to avoid DoS attack
                while (expected < shutdown.length()) {
                    
if (random == null)
                        random 
= new Random();
                    expected 
+= (random.nextInt() % 1024);
                }
                
while (expected > 0) {
                    
int ch = -1;
                    
try {
                        ch 
= stream.read();
                    } 
catch (IOException e) {
                        log.warn(
"StandardServer.await: read: ", e);
                        ch 
= -1;
                    }
                    
if (ch < 32)  // Control character or EOF terminates loop
                        break;
                    command.append((
char) ch);
                    expected
--;
                }
            } 
finally {
// Close the socket now that we are done with it
                try {
                    
if (socket != null) {
                        socket.close();
                    }
                } 
catch (IOException e) {
// Ignore
                }
            }

// Match against our command string
            boolean match = command.toString().equals(shutdown);
            
if (match) {
                log.info(sm.getString(
"standardServer.shutdownViaPort"));
                
break;
            } 
else
                log.warn(
"StandardServer.await: Invalid command '"
                        
+ command.toString() + "' received");
        }
    }

    
finally {
        ServerSocket serverSocket 
= awaitSocket;
        awaitThread 
= null;
        awaitSocket 
= null;
// Close the server socket and return
        if (serverSocket != null) {
            
try {
                serverSocket.close();
            } 
catch (IOException e) {
// Ignore
            }
        }
    }

posted @ 2011-05-13 11:31 xsong 阅读(529) | 评论 (0)编辑 收藏

 

class A {
  
void call() {}  
}
  
class B extends A {
  
void call() {}  
}
  
class C {
  
void call() {}  
}
 
void foo(A a){
}

A a
=new A();
foo(a); 

C c
=new C();
foo(c);
java编译器无法通过, 因为C不是A或者A的子类 虽然 C 中也有 call 方法。

scala 中可以通过 结构类型(Structural)实现
class A {
  def call() 
{
    println(
"a class")
  }

}

class B extends A {override def call() {}}
class C {
  def call() 
{
    println(
"c class")
  }

}


object Call 
{
  def main(args: Array[String]) 
{
    def foo[T 
<{ def call() }](a : T) {
      a.call()
    }

    val a 
= new A()
    val c 
= new C()
    foo(a)
    foo(c)
    println()
  }

}

不过觉得  def foo[T <: { def call() }](a : T)  这样的写法 不如动态语言(ruby, groovy..)看起来自然。

posted @ 2010-01-12 18:02 xsong 阅读(133) | 评论 (0)编辑 收藏

    java中的泛型:
List<String> s1=new ArrayList<String>();
        s1.add(
"hello");
当在s1中添加 String 类型以外的对象时,编译器会报错。
s1.add(new Date());
scala 中是用 [] 代替 java 中的<> 表达泛型。scala 在new ArrayList时,不需要指定String类型,得益与scala 的类型推断。
val strs : List[String]=new ArrayList()
scala 中定义泛型列表,和java中类似
class Link[T](val head: T, val tail: Link[T]) 
协变的定义:    假设有类G(或者接口和特征) 和类型T1,T2  。 在T1是T2的子类的情况下, 如果G<T1> 也是G2<T2>的子类,则类G是协变的。

当我定义一个列表对象li,并定义一个ln为li 的别名
 List<Integer> li=new ArrayList<Integer>();
        li.add(
1);
        List
<Number> ln=li;

这样的方式,编译器不能通过。
通过协变,可以实现上诉功能
class Link[+T](val head : T, val tail: Link[T]) {}

def main(args : Array[String])
{
      val ln : Link[Integer]
=new Link[Integer](1,null)
      val lnn : Link[Number]
=ln
      println(lnn.head)
}


但是如果试图加入一个方法,追加一个参数,并返回Link, 则会产生编译错误
class Link[+T](val head : T, val tail: Link[T]) {

 def prepend(newHead: T): Link[T] 
= new Link(newHead, this)
}

 
实际上,范型变为协变之后就不能把类型参数不加修改的放在成员方法的参数上(这里是newHead)了。但是,通过将成员方法定义为范型,并按照如下所示描述后就可以避免该问题了

class Link[+T](val head: T, val tail: Link[T]) {  
    def prepend[U 
>: T](newHead: U): Link[U] = new Link(newHead, this)  
}
 
scala 逆变,类似协变
假设有类 G 和类型T1,T2, 在T1 是T2的子类的情况,如果G[T2]是G[T1]的子类, 则G为逆变。
假设含有 apply的类 LessThan(apply 的逻辑 当a<b 时,返回true 否则返回false)
abstract class LessThan[T] {
  def apply(a: T, b: T): Boolean
}
val hashCodeLt: LessThan[Any] = new LessThan[Any] {
      def apply(a: Any, b: Any): Boolean 
= a.hashCode < b.hashCode
    }


    val strLt: LessThan[String] 
= hashCodeLt

    
assert(true ,strLt("a","b"))
在非变的情况 编译器会报错:Error:Error:line (18)error: type mismatch;
found   : xxx.LessThan[Any]
required: xxx.LessThan[String]
val strLt: LessThan[String] = hashCodeLt
在需要LessThan[Any]的地方使用了LessThan[String],由此看来LessThan不是逆变的,也不是协变,可以成为非变。
但是在类的定义前加一个 - 符号,使用逆变, 代码则可编译过去了。
abstract class LessThan[-T] {
  def apply(a: T, b: T): Boolean
}



posted @ 2010-01-12 17:20 xsong 阅读(702) | 评论 (0)编辑 收藏

java 有很庞大的类库资源,但是 被声明成 final 的类不允许继承 例如 String , 怎样扩展java及第三方类库 scala提供了很灵活的方式

当 scala 使用 implicit 隐式转化时 ,  scala 编辑器发现对象的类型不匹配时,不会直接报错,而会在代码中尝试匹配implicit声明的object, 当然,相同方法签名的类必须唯一。
举个小例子,实现在字符串前后 添加 "**" 的操作。

当然 例子本事无实际意义, 只是说明implicit的用法而已 
 1object implicits {
 2
 3  implicit  def strWrapper(s : String)={
 4    new {
 5      def wrap= "**"+s+"**"
 6    }

 7  }

 8  def main(args: Array[String]) {
 9    val s = "hello"
10    println(s.wrap)  // **hello**
11  }

12}

当scala的编译器 编译 s.wrap 时,因为 String 类中没有 wrap方法,编译器会寻找代码中方法签名相同的 strWrapper(s :String),
输出  **hello**

另外一种写法 :

 1object implicits {
 2
 3  class StrWrapper(s : String){
 4    def wrap="**"+s+"**"
 5  }

 6  def main(args: Array[String]) {
 7    implicit def wrapper(s :String)=new StrWrapper(s)
 8    val s = "hello" 
 9    println(s.wrap) // print **hello**
10  }

11}

posted @ 2009-12-23 17:17 xsong 阅读(4139) | 评论 (0)编辑 收藏