Java多线程 final和static变量

写了一个多线程中有关final和static的例子,遇到问题了。

 public class MyThread implements Runnable
{
    int i = 0;
    int a = 20;
    static int b = 20;
    static int c = 20;
    static int d = 20;
    final int finalIntNoStatic = a++;
    static int staticInt = b++;
    final int finalInt = c++;
    static final int STATIC_FINAL_INT = d++;

    @Override
    public void run()
    {
        while (i < 10)
        {
            System.out.println("i=" + i + ",finalIntNoStatic=" + finalIntNoStatic + ",a=" + a
                    + ",staticInt=" + staticInt + ",b=" + b + ",finalInt=" + finalInt + ",c=" + c
                    + ",STATIC_FINAL_INT=" + STATIC_FINAL_INT + ",d=" + d);
            i++;
        }
    }
}
 public class MultiThread 
{
    public static void main(String[] args)
    {

        for (int i = 0; i < 5; i++)
        {
            Thread aThread=new Thread(new MyThread());
            aThread.start();
        }
        System.out.println("Run in main thread");
    }
}

最后打印结果为:

 i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
Run in main thread
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=25,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=25,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=25,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=25,STATIC_FINAL_INT=20,d=21

我的问题是为什么c的值一直是25,,编译和运行过程中finalInt和c的赋值顺序是怎样的

5个回答

c为什么都是25,因为在main方法中循环只有5次,执行速度非常快,创建了5个MyThread需要的时候可以忽略不计。当创建完后,都还没开始执行子线
程的run方法。但这种结果不是必然的。比如在for循环时,让主线程sleep 100毫秒,你会看到不一样的结果。

     public static void main(String[] args) {
        System.out.println("Run in main thread");
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Run in main thread");
            Thread aThread = new Thread(new MyThread());
            aThread.start();

        }

    }
 Run in main thread
Run in main thread
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=20,c=21,STATIC_FINAL_INT=20,d=21
Run in main thread
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=21,c=22,STATIC_FINAL_INT=20,d=21
Run in main thread
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=22,c=23,STATIC_FINAL_INT=20,d=21
Run in main thread
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=23,c=24,STATIC_FINAL_INT=20,d=21
Run in main thread
i=0,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=1,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=2,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=3,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=4,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=5,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=6,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=7,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=8,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21
i=9,finalIntNoStatic=20,a=21,staticInt=20,b=21,finalInt=24,c=25,STATIC_FINAL_INT=20,d=21

u013894427
二仪式 麻烦看一下我后面的回答对不对。谢谢。
3 年多之前 回复
u013894427
二仪式 回复wolf犭良: b和d也是静态变量属于类变量,如果b和d不被重新赋值,那么b和d为什么会在每个线程中都保持21,而不是像c一样递增?
3 年多之前 回复
ldz_wolf
wolf犭良 在创建对象的时候就已经对变量进行赋值了,而run方法是要在thread.start()之后才会被调用。c是静态变量属于类变量,在类被第一次调用就会赋值第一次赋值后,后面再创建对象不会 再赋值,而finalInt每次创建对象是都会被创建并赋值
3 年多之前 回复
u013894427
二仪式 没有延时全是25,是否可以理解为函数运行是在赋值之后才运行的。那么第二个问题,c和finalInt的赋值顺序是怎样的,他俩在各个线程中是不同的?
3 年多之前 回复
 static int b=20;
 static int staticInt=b++;
 //相当于
 static int b=20;
 b=b+1;
 static int staticInt=b;
 //b是静态变量属于类变量,所以第二次及之后不会执行 static int b=20;
 //static int staticInt=b++;属于初始化,只会执行一次,所以staticInt的值一直是20;
 //b=b+1属于staticInt的初始化语句,所以之后也不会执行。所以b的值一直是21
ldz_wolf
wolf犭良 是这样的。
3 年多之前 回复
 static int c=20;
 final int staticInt=c++;
 //相当于
 static int c=20;
 c=c+1;
 final int finalInt=c;
 //c是静态变量属于类变量,所以第二次及之后不会执行 static int c=20;
 //finalInt不是静态变量,所以其初始语句会继续执行。
 //final int finalInt=c++;属于初始化,不止执行一次,所以finalInt的值会一直增大;
 //c=c+1属于finalInt的初始化语句,所以会继续执行。所以c的值一直会一直增大;

  static int d=20;
 final static int STATIC_FINAL_INT=d++;
 //相当于
 static int d=20;
 d=d+1;
 final static int STATIC_FINAL_INT=d;
 //d是静态变量属于类变量,所以第二次及之后不会执行 static int c=20;
 //STATIC_FINAL_INT 是静态变量,所以其初始语句不会继续执行。
 //fina staticl int STATIC_FINAL_INT=d++;属于初始化,只执行一次,所以STATIC_FINAL_INT的值不会改变;
 //d=d+1属于STATIC_FINAL_INT的初始化语句,所以不会继续执行。所以d的值不会改变;

更正:d++应该是赋值之后才进行+1操作的。

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
java 多线程方法加锁获取自增变量重复问题
/** * 测试多线程并发获取唯一子增长的值 * @author Administrator * */ public class BB { private int increment = 0; final static Set<Integer> set = new HashSet<Integer>(); final static List<Integer> list = new ArrayList<Integer>(); public synchronized int getauto() { return increment++; } public static void main(String[] args) throws Exception { final BB b = new BB(); Vector<Thread> workers = new Vector<Thread>(); for (int i = 0; i < 2; i++) { final Thread t = new Thread(new Runnable() { @Override public void run() { synchronized (this) { for (int j = 0; j < 10000; j++) { int num = b.getauto(); System.out.println(String.valueOf(num)); set.add(num); list.add(num); } } } }); workers.add(t); t.setName("thread-" + i); t.start(); } for (Thread t : workers) { t.join(); } System.out.println("set size :" + set.size()); System.out.println("list size :" + list.size()); } } list和set的size不同
static
在多线程并发的环境下使用static 变量是不安全的,看到很多实例这样使用:private final static ThreadLocal threadlocal=new ThreadLocal();为什么ThreadLocal使用static就没有这个问题呢?还有日志的:private static Logger log=Logger.getLogger(XX.class);
java多线程 参数已经传入构造方法 进入run方法时参数却被改变
请教各位大神:我在for循环里面执行线程,遇到一个问题,代码如下: private static final ExecutorService executors = Executors.newScheduledThreadPool(10); ...... for(...){ executors.execute(new PublishThread(map)); } PublishThread实现了Runnable方法,它有一个私有成员变量map,在PublishThread有一个构造函数,接受了上面的map参数,并将它赋给私有成员变量map。调试的时候发现到构造函数里面时,map值与for循环里面传过来的值是匹配的,但是到run方法里面时,map里面的值却被改变。比如3次for循环传进的参数分别为:{classId=10295, class_ids=[10295, 10325, 10327]},{classId=10292, class_ids=[10292]},{classId=10293, class_ids=[10293]},但是3次run里面看到的值确是{classId=10295,, class_ids=[10293]},{classId=10292,, class_ids=[10293]},{classId=10293,, class_ids=[10293]},这已经不是顺序乱掉的问题(顺序乱本正常),而是变量里面乱了。请问这有可能是什么原因导致的呢?有什么措施可以让这个map不被改变?
java怎么用多线程并发运行for?
如果把下面的改成十个线程并发运行不同的for语句,,就我最下面写好的那个方法,参数用定义好的数组里面的十个int变量,请问要怎么写? ``` public static void main(String[] args) { for(Thread t:getThreads()){ t.start(); } } public static Thread[] getThreads(){ Thread[] thread = new Thread[10]; for(int i=0;i<10;i++){ final Integer num = new Integer(i); thread[i] = new Thread(new Runnable(){ public void run() { int j=5; while(j-->0){ System.out.println("this is thread"+num); } } }); } return thread; } public static void bbq(int a){ for(int b=a;b<a+2;b++){ System.out.println("for循环"+"起始值为"+a+"终止值为"+(a+2)); } } ```
常量池,线程池 什么时候创建什么时候销毁? 有多大?
# 常量池,线程池 什么时候创建什么时候销毁? 有多大? 为什么 内部类访问外部类的对象或是成员变量是必须加上final? 可以再加上static一起修饰码?
log4j2是否存在线程安全问题
应用中定义了一个日志打印切面,切面中定义了一些静态的logger成员变量,类似于这样 private static final Logger logger = LoggerFactory.getLogger(ApiLogAspect.class); 现在的问题是多个线程使用同一个logger是否会存在安全问题。 谢谢各位大佬各显神通
急求java高手,帮忙看下面的游戏代码,为何只能运行界面类然后其他都看不见也不能玩
//子弹Bullet类 package hy; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; public class Bullet { //坐标 public int x,y; //子弹大小 public int width,height; //子弹杀伤力 public int kill; //速度 public int speed; //子弹图片 public String img; //是否存活 public boolean isLive=true; //子弹类型(好坏) public boolean isGood; public void drawBullet(Graphics g) { Toolkit tk=Toolkit.getDefaultToolkit(); Image img1=tk.getImage(Bullet.class.getClassLoader().getResource("hy.image/"+img)); //画图 g.drawImage(img1, x,y,width,height,null); } } //Person 类 package hy; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.Toolkit; import javax.tools.Tool; public class Person { //敌机坐标 private int x,y; private int width,height; public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getHp() { return hp; } public void setHp(int hp) { this.hp = hp; } public int getKill() { return kill; } public void setKill(int kill) { this.kill = kill; } public String getImgurl() { return imgurl; } public void setImgurl(String imgurl) { this.imgurl = imgurl; } public int getSpeed() { return speed; } public void setSpeed(int speed) { this.speed = speed; } //血量 private int hp; public Person(int x, int y, int width, int height, int hp, int kill, String imgurl, int speed) { super(); this.x = x; this.y = y; this.width = width; this.height = height; this.hp = hp; this.kill = kill; this.imgurl = imgurl; this.speed = speed; } //杀伤力 private int kill; //定义图片路径 private String imgurl; //是否存活 public boolean isLive=true; //速度 private int speed; public void drawPerson(Graphics g) { //定义系统工具类 Toolkit tk=Toolkit.getDefaultToolkit(); //创建图片对象 Image img=tk.getImage(Person.class.getClassLoader().getResource("hy.image/"+imgurl)); g.drawImage(img,x,y,width,height,null); move(); } public void move() { y+=speed; if(y>=MyFrame.HEIGHT) { isLive=false; } //捡查子弹是否出屏幕 for (int i = 0; i < MyFrame.bulletAll.size(); i++) { if(MyFrame.bulletAll.get(i).y<0) { MyFrame.bulletAll.get(i).isLive=false; } } this.hitPerson(); this.hitBullet(); } //反回当前敌机的矩形 public Rectangle getPersonRectangle() { return new Rectangle(x,y,width,height); } //判断相撞 public void hitPerson() { //得到敌机矩形 Rectangle personRec=this.getPersonRectangle(); //得到主机矩形 Rectangle myRec=new Rectangle(MyFrame.my_x,MyFrame.my_y,55,60); if(myRec.intersects(personRec)==true) { this.isLive=false; //产生爆炸效果 Explode e=new Explode(x,y); //将e放入爆炸效果集合 MyFrame.explodeAll.add(e); } } //判断和玩家子弹的相撞 public void hitBullet() { //得到敌机矩形 Rectangle personRec=this.getPersonRectangle(); //得到子弹的矩形 for (int i = 0; i < MyFrame.bulletAll.size(); i++) { Rectangle bulletRec=new Rectangle(MyFrame.bulletAll.get(i).x,MyFrame.bulletAll.get(i).y,20,20); if(personRec.intersects(bulletRec)==true) { MyFrame.score+=10; this.isLive=false; //产生爆炸效果 Explode e=new Explode(x,y); //将e放入爆炸效果集合 MyFrame.explodeAll.add(e); } } } } //MyFrame界面类 package hy; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Random; import javax.swing.JFrame; public class MyFrame extends Frame { public static final int WIDTH=900; public static final int HEIGHT=700; public static int my_x=450; public static int my_y=600; //分数 public static int score=0; //定义变量,专门表示键盘按下的键 public static boolean a=false;public static boolean s=false; public static boolean d=false;public static boolean w=false; public static boolean j=false; //敌机的集合 public ArrayList<Person> personAll=new ArrayList<Person>(); //存放爆炸效果的集合 public static ArrayList<Explode> explodeAll=new ArrayList<Explode>(); //存放子弹的集合 public static ArrayList<Bullet> bulletAll=new ArrayList<Bullet>(); public MyFrame() { this.setTitle("雷电飞机射击"+score); this.setSize(WIDTH,HEIGHT); this.setLocationRelativeTo(null); this.setResizable(false); this.addWindowListener(new MyWindowClose()); //添加键盘监听器 this.addKeyListener(new MyKeyDown()); this.setVisible(true); MyThread t=new MyThread(); t.start(); } //定义背景Y座标 int bg_y=0; @Override public void paint(Graphics g) { Toolkit tk=Toolkit.getDefaultToolkit(); Image bg_img=tk.getImage(MyFrame.class.getClassLoader() .getResource("hy.image/bg2.jpg")); g.drawImage(bg_img, 0, bg_y, WIDTH, HEIGHT, null); bg_y+=10; g.drawImage(bg_img, 0, -HEIGHT+bg_y, WIDTH, HEIGHT, null); //判断bg_y的值是否超过窗体的高度 if(bg_y>HEIGHT) { bg_y=0; } Image my_img=tk.getImage(MyFrame.class.getClassLoader() .getResource("hy.image/my_img.jpg")); g.drawImage(my_img, my_x, my_y, 55, 60, null); //创建随机对象 Random rd=new Random(); if(rd.nextInt(10)==5) { //创建敌机 Person person=new Person(rd.nextInt(850), 45, 32, 58, 100, 100, "enemy1.jpg", 15); personAll.add(person); } for (int i = 0; i < personAll.size(); i++) { Person person=personAll.get(i); if(person.isLive) { person.drawPerson(g); } else personAll.remove(person); } //绘画爆炸 for (int i = 0; i < explodeAll.size(); i++) { Explode e=explodeAll.get(i); //判断是否是活字弹 if(e.isLive) { e.drawExplode(g); } else { explodeAll.remove(e); } } //绘画子弹 for (int i = 0; i < bulletAll.size(); i++) { Bullet bullet=bulletAll.get(i); //判断是否是活子弹 if(bullet.isLive) { bullet.drawBullet(g); } else { bulletAll.remove(bullet); } } this.setTitle("雷电飞机射击游戏 分数:"+score); } public void move() { if(a) MyFrame.my_x-=20; if(d) MyFrame.my_x+=20; if(s) MyFrame.my_y+=20; if(w) MyFrame.my_y-=20; if(j) { Fire(); } } //开火方法 public void Fire() { Bullet bullet=new Bullet(); bullet.x=my_x+22; bullet.y=my_y+30; bullet.img="bullet.jpg"; bullet.speed=40; bullet.width=20; bullet.height=20; bulletAll.add(bullet); } Image img=null; @Override public void update(Graphics g) { if(img==null) { img=this.createImage(WIDTH, HEIGHT); } //利用img创建虚拟画笔 Graphics gb=img.getGraphics(); //调用paint方法 paint(gb); //利用真实的画笔g来画图片 g.drawImage(img, 0,0,WIDTH,HEIGHT,null); } public static void main(String[] args) { new MyFrame(); } //内部类,线程类,用来刷新当前窗体S class MyThread extends Thread { @Override public void run() { while(true) { repaint(); //每时每刻都判断是否要移动飞机 move(); try { //让子弹前进,速度要比玩家速度快很多 for (int i = 0; i < bulletAll.size(); i++) { Bullet bullet=bulletAll.get(i); bullet.y-=bullet.speed; } Thread.sleep(65); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } //MyWindowClose类 package hy; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; class MyWindowClose extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { System.exit(0); } } class MyKeyDown extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_A: MyFrame.a=true; break; case KeyEvent.VK_S: MyFrame.s=true; break; case KeyEvent.VK_D: MyFrame.d=true; break; case KeyEvent.VK_W: MyFrame.w=true; break; case KeyEvent.VK_J: MyFrame.j=true; break; default: break; } } @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_A: MyFrame.a=false; break; case KeyEvent.VK_S: MyFrame.s=false; break; case KeyEvent.VK_D: MyFrame.d=false; break; case KeyEvent.VK_W: MyFrame.w=false; break; case KeyEvent.VK_J: MyFrame.j=false; break; default: break; } } } //Explode爆炸类 package hy; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; public class Explode { //坐标 private int x; private int y; //定义爆炸显示的图片 String img[]={"boom1.jpg","boom2.jpg","boom3.jpg","boom4.jpg","boom5.jpg","boom6.jpg","boom7.jpg","boom8.jpg","boom9.jpg"}; //爆炸的生命 public boolean isLive=true; //定义下标 private int index=0; public Explode(int x, int y) { this.x = x; this.y = y; index++; } public void drawExplode(Graphics g) { //得到工具类 Toolkit tkToolkit=Toolkit.getDefaultToolkit(); //得到图片对象 //得到数组中的图片 String image=img[index]; Image img1=tkToolkit.getImage(Explode.class.getClassLoader().getResource("hy.image/"+image)); g.drawImage(img1, x,y,null); index++; if(index>=img.length) { index=0; //生命消失 isLive=false; } } } //Sound背景音乐类 package hy; import java.applet.AudioClip; import java.io.*; import java.applet.Applet; import javax.swing.JFrame; import java.net.MalformedURLException; import java.net.URL; public class Sound extends JFrame{ public Sound(){ super(); } public static void main(String args[]) { try { URL cb; File f = new File("hy.music\\t.wav"); //引号里面的是音乐文件所在的绝对路径 cb = f.toURL(); AudioClip aau; aau = Applet.newAudioClip(cb); //aau.play(); aau.loop(); //循环播放 aau.play() 单曲 aau.stop()停止播放 Sound frame=new Sound(); //frame.setBounds(0, 0, 300, 200); //frame.setVisible(true); } catch (MalformedURLException e) { e.printStackTrace(); } } }
从任何类中都能获取request中的属性,只能用线程局部变量吗?
web应用中实现国际化,基于request.getLocale获取请求者的国家语言,所以很多类中都会用到: ResourceBundle messages = ResourceBundle.getBundle("message",locale); 来获取适当的资源文件,因此需要在所有类中都能取到request中的locale属性。 我可以创建一个线程局部变量来存放它,如: public class I18nUnit { private static final ThreadLocal<String> locale = new ThreadLocal<String>(); ...... public static String getLocale() { if (locale.get() == null) { return ""; } return (String) locale.get(); } } 在servlet的doService方法开头设置这个变量,然后在任意类中用I18nUnit.getLocale()获取,能够实现。 但我觉得这个办法挺另类挺绕的,应该有更容易的获取方式吧? [b]问题补充:[/b] lovewhzlq:那么在任意类中如何获取session呢?我原来都是request.getSession(),任意类中如果取不到request,session也得不到啊 [b]问题补充:[/b] bohemia: 有些普通类中要抛出异常,异常消息需要是国际化的,抛出后是要展示给用户看的,您认为有其它方法可以解决吗?
关于ThreadLocal内存泄漏
看到很多说ThreadLocal内存泄漏的都是把ThreadLocal变量置为null后说value一直存在 ,造成内存泄漏。那么再利用线程池的环境中,如果把ThreadLocal变量声明为static final的,是不是一定不会发生内存泄漏的可能了?或者说对于一个线程来说,ThreadLocalMap中最多有一条关于这个ThreadLocal变量的记录? 因为即使线程不死亡一直存在,但是map里的key是一样的,所以set方法只是在覆盖旧值?
Hibernate中的session的save方法。
我正在学习hibernate框架,然后在做一个插入的时候遇到了一个问题。通过跟踪我发现在执行session.save(obj);方法时,程序就不动了。并且在获取session时还打印出下面红色的信息。 请问一个是什么原因以及怎么解决呢? ![图片说明](https://img-ask.csdn.net/upload/201604/30/1462019362_918790.png) ``` public int insertClient(Client client) { // TODO Auto-generated method stub //HibernateUtil.closeSession(); System.out.println("client insert1 :"); Session session = HibernateUtil.currentSession(); //System.out.println(session); System.out.println("client insert2 :"); Transaction transaction = session.beginTransaction(); System.out.println("client insert3 :"); System.out.println(client); Integer s= (Integer) session.save(client); System.out.println("client insert4 :"+s); try { transaction.commit(); } catch (Exception e) { transaction.rollback(); } finally { HibernateUtil.closeSession(); } System.out.println("row :"+s); return s; } ``` ``` public class HibernateUtil { public static final SessionFactory sessionFactory; static { try { // 使用默认的hibernate.cfg.xml配置文件创建Configuration实例 Configuration cfg = new Configuration() .configure(); // 以Configuration实例来创建SessionFactory实例 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(cfg.getProperties()).build(); sessionFactory = cfg.buildSessionFactory(serviceRegistry); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } // ThreadLocal可以隔离多个线程的数据共享,因此不再需要对线程同步 public static final ThreadLocal<Session> session = new ThreadLocal<Session>(); public static Session currentSession() throws HibernateException { Session s = session.get(); System.out.println("session get:"); // 如果该线程还没有Session,则创建一个新的Session if (s == null) { s = sessionFactory.openSession(); // 将获得的Session变量存储在ThreadLocal变量session里 session.set(s); } return s; } public static void closeSession() throws HibernateException { Session s = session.get(); if (s != null) s.close(); session.set(null); } } ```
“构造一个虚拟位置信息给谷歌地图,让其定位错误”失败
用以下代码“构造一个虚拟位置信息给谷歌地图,让其定位错误”无法实现,给位大神指点迷津,小弟开始研究Android编程不久,有点小白望谅解 正常情况下是:在本应用横纵有一个数据库,记录用户对不同需要获取位置信息的应用按精确度进行分类,分别为城镇级,精确级,街道级,不同级别对应的位置模糊程度不同,虚构的位置信息也不同 代码如下: package com.example.hermit; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Random; import android.app.ActivityManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.widget.Toast; public class service extends Service { LocationManager locationManager; private PackageManager pm;// Package Manager(包管理)-用来找到关于安装在设备上的应用程序包的相关信息。 private ArrayList<String> default1 = new ArrayList<String>();// 城镇;创建default1来保存字符串数组 private ArrayList<String> default2 = new ArrayList<String>();// 街道;创建default2来保存字符串数组 private ArrayList<String> default3 = new ArrayList<String>();// 精准;创建default3来保存字符串数组 private ArrayList<String> user1 = new ArrayList<String>();// 城镇 private ArrayList<String> user2 = new ArrayList<String>();// 街道 private ArrayList<String> user3 = new ArrayList<String>();// 精准 private Strategy_DB DB = new Strategy_DB(this); double test1; private String mocLocationProvider; private String currentProvider; private String Provider; // Android的location定义新的变量 private Location currentLocation; Location LOCtmp; Location Location; Location Loc; Location l; // 精确 double latitude;// 经度 double longitude;// 纬度 // 城镇 double latitude1; double longitude1; // 街道 double latitude2; double longitude2; double ltd_tmp; double lng_tmp; private String AN; private String TAG = "service"; static final int DELAY = 4000; // 相当于定义常量DELAY String name; int flag = 0; static final String ACTION_FOREGROUND = "com.example.android.apis.FOREGROUND"; static final String ACTION_BACKGROUND = "com.example.android.apis.BACKGROUND"; private final IBinder mBinder = new localBinder(); /* * Handler在android里负责发送和处理消息。它的主要用途有:   1)按计划发送消息或执行某个Runnanble(使用POST方法); *   2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)/用来向不属于自己的线程的队列中加入某个动作 */ Handler handler; Runnable runnable; private static final Class<?>[] mSetForegroundSignature = new Class[] { boolean.class }; private static final Class<?>[] mStartForegroundSignature = new Class[] { int.class, Notification.class }; private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class }; private NotificationManager mNM; private Method mSetForeground; private Method mStartForeground; private Method mStopForeground; private Object[] mSetForegroundArgs = new Object[1]; private Object[] mStartForegroundArgs = new Object[2]; private Object[] mStopForegroundArgs = new Object[1]; /* *  可以看出,对于一个对象的方法调用来说,如果这个方法能够被分派出去, * 如上面的“hello”方法,可以在InvokeTestor1类中找到,就被分派给InvokeTestor1类的“hello”方法; * 如果不能被分派,如上面的“foo”方法,则调用“invokeMethod”方法 */ void invokeMethod(Method method, Object[] args) { try { method.invoke(this, args); } catch (InvocationTargetException e) { // Should not happen. Log.w("ApiDemos", "Unable to invoke method", e); } catch (IllegalAccessException e) { // Should not happen. Log.w("ApiDemos", "Unable to invoke method", e); } } /** * This is a wrapper around the new startForeground method, using the older * APIs if it is not available. */ void startForegroundCompat(int id, Notification notification) { // If we have the new startForeground API, then use it. if (mStartForeground != null) { mStartForegroundArgs[0] = Integer.valueOf(id); mStartForegroundArgs[1] = notification; Log.d(TAG, "Updater running"); invokeMethod(mStartForeground, mStartForegroundArgs); return; } // Fall back on the old API. mSetForegroundArgs[0] = Boolean.TRUE; Log.d(TAG, "Updater sdsf"); invokeMethod(mSetForeground, mSetForegroundArgs); mNM.notify(id, notification); } /** * This is a wrapper around the new stopForeground method, using the older * APIs if it is not available. */ void stopForegroundCompat(int id) { // If we have the new stopForeground API, then use it. if (mStopForeground != null) { mStopForegroundArgs[0] = Boolean.TRUE; invokeMethod(mStopForeground, mStopForegroundArgs); return; } // Fall back on the old API. Note to cancel BEFORE changing the // foreground state, since we could be killed at that point. mNM.cancel(id); mSetForegroundArgs[0] = Boolean.FALSE; invokeMethod(mSetForeground, mSetForegroundArgs); } public class localBinder extends Binder { service getService() { return service.this; } } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.i(TAG, "this is on binder"); return null; } public void OnCreate() { // 获得系统级的服务Notification Manager,调用getSystemService()方法实现 mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // 为了兼容Android1的代码。即如果mStartForeground / mStopForeground // 为空就表示是Android1的环境。 try { mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature); mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); return; } catch (NoSuchMethodException e) { // Running on an older platform. mStartForeground = mStopForeground = null; } try { mSetForeground = getClass().getMethod("setForeground", mSetForegroundSignature); } catch (NoSuchMethodException e) { // 抛出一个异常 throw new IllegalStateException( "OS doesn't have Service.startForeground OR Service.setForeground!"); } } public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "recived start id" + startId + ":" + intent); // //获得系统级的服务Location Manager,调用getSystemService()方法实现 locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); // mocLocationProvider 存放gps信息 mocLocationProvider = LocationManager.GPS_PROVIDER; // 根据设置的Criteria对象,获取最符合此标准的provider对象 currentProvider = locationManager.getProvider( LocationManager.GPS_PROVIDER).getName(); // 获取网络位置信息 Provider = locationManager .getProvider(LocationManager.NETWORK_PROVIDER).getName(); // 根据当前provider对象获取最后一次位置信息 l = locationManager.getLastKnownLocation(Provider); latitude = l.getLatitude();// 精确 longitude = l.getLongitude(); chose(); if (flag == 1) { ltd_tmp = latitude1;// 城镇 lng_tmp = longitude1; } if (flag == 2) { ltd_tmp = latitude2;// 街道 lng_tmp = longitude2; } if (flag == 3) { ltd_tmp = latitude;// 精确 lng_tmp = longitude; } if (flag == 0) { ltd_tmp = latitude1;// 精确 lng_tmp = longitude1; } //创建 一个 “用于模拟的坐标提供者” // 创建一个仿真位置信息并添加到当前正在运行的provider中 locationManager.addTestProvider(mocLocationProvider, false, false, false, false, false, false, false, 0, 5); // 让创建好的仿真位置信息对于正在运行的provider可用。并且该值会替代原有真实provider中的数据 locationManager.setTestProviderEnabled(mocLocationProvider, true); Location = new Location(mocLocationProvider); // Location.setTime(currentLocation.getTime() ); // Location.setLatitude(Loc.getLatitude()); // Location.setLongitude(Loc.getLongitude()); float x = 5.0f, y = 0.0f, s = 10.0f; Location.setAccuracy(x);// 设置精度 Location.setSpeed(s); Location.setAltitude(y);// 设置 // Log.e("location", Location.toString()); // 获得已安装的应用程序信息 。可以通过getPackageManager()方法获得 pm = getPackageManager(); // 通过系统服务获取ActivityManager ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); // 获得当前正在运行的activity ComponentName cn = am.getRunningTasks(1).get(0).topActivity; name = cn.getPackageName(); // 在android中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知。 handler = new Handler(); // 实现多线程 runnable = new Runnable() { public void run() { DB.closeDB();// 关闭数据库 DB.openDB();// 打开数据库 opDB(); ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); ComponentName cn2 = am.getRunningTasks(1).get(0).topActivity; String cmp = cn2.getPackageName(); // Log.d(TAG, "Updater running"); if (!name.equals(cmp) && cmp.equals("com.example.hermit")) { name = cmp; } if (!name.equals(cmp) && !cmp.equals("com.android.launcher") && !cmp.equals("com.example.hermit")) { Log.d(TAG, cmp); try { ApplicationInfo info = pm.getApplicationInfo(cmp, 0); AN = (String) pm.getApplicationLabel(info);// AN表示获取的应用标签 Log.i("AN", AN); } catch (NameNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } chose(); if (flag == 1) { ltd_tmp = latitude1;// 城镇 lng_tmp = longitude1; } if (flag == 2) { ltd_tmp = latitude2;// 街道 lng_tmp = longitude2; } if (flag == 3) { ltd_tmp = latitude;// 精确 lng_tmp = longitude; } if (flag == 0) { ltd_tmp = latitude1;// 精确 lng_tmp = longitude1; } Location.setTime(System.currentTimeMillis()); Location.setLatitude(ltd_tmp); Location.setLongitude(lng_tmp); //locationManager.setTestProviderLocation(mocLocationProvider, Location); Log.e("l", l.toString()); Log.i("test1", "lat long" + latitude + longitude); Log.i("location", Location.toString()); Log.i("location", "flag=" + flag + " " + ltd_tmp + lng_tmp); try { locationManager.setTestProviderLocation( mocLocationProvider, Location); } catch (IllegalArgumentException e) { Log.d("test", "location error"); String mess = e.getLocalizedMessage(); Log.d("test", mess); } locationManager.requestLocationUpdates(currentProvider, 0, 0, locationListener); currentLocation = locationManager .getLastKnownLocation(currentProvider); if (currentLocation == null) { // Log.d("test","location error"); locationManager.requestLocationUpdates(currentProvider, 0, 0, locationListener); currentLocation = locationManager .getLastKnownLocation(currentProvider); } else { // Log.e("location", currentLocation.toString()); } // 获取当前运行的activity并放于cn2中 // ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); // ComponentName cn2 = am.getRunningTasks(1).get(0).topActivity; // String cmp = cn2.getPackageName(); // // // Log.d(TAG, "Updater running"); // if (!name.equals(cmp) && cmp.equals("com.example.hermit")) { // name = cmp; // } // if (!name.equals(cmp) && !cmp.equals("com.android.launcher") // && !cmp.equals("com.example.hermit")) { // Log.d(TAG, cmp); // try { // ApplicationInfo info = pm.getApplicationInfo(cmp, 0); // AN = (String) pm.getApplicationLabel(info);// AN表示获取的应用标签 // Log.i("AN", AN); // } catch (NameNotFoundException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } Log.d("falg", "flag=" + flag); // chose(); // if (flag == 1) { // ltd_tmp = latitude1;// 城镇 // lng_tmp = longitude1; // } // if (flag == 2) { // ltd_tmp = latitude2;// 街道 // lng_tmp = longitude2; // } // if (flag == 3) { // ltd_tmp = latitude;// 精确 // lng_tmp = longitude; // } // if (flag == 0) { // ltd_tmp = latitude1;// 精确 // lng_tmp = longitude1; // } // Location.setTime(System.currentTimeMillis()); // Location.setLatitude(ltd_tmp); // Location.setLongitude(lng_tmp); // locationManager.setTestProviderLocation(mocLocationProvider, Location); // 监听到用户打开了需要访问位置信息的应用 Log.d("falg", "flag=" + flag); if (flag == 1) { Intent i = new Intent(service.this, Dialog.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Bundle b = new Bundle(); b.putString("textview", "粒度策略:城镇级 "); i.putExtras(b); startActivity(i); flag = 0; } if (flag == 2) { Intent i = new Intent(service.this, Dialog.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Bundle b = new Bundle(); b.putString("textview", "粒度策略:街道级 "); i.putExtras(b); startActivity(i); flag = 0; } if (flag == 3) { Intent i = new Intent(service.this, Dialog.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Bundle b = new Bundle(); b.putString("textview", "粒度策略:精确级 "); i.putExtras(b); startActivity(i); flag = 0; } name = cmp; } handler.postDelayed(this, 3000); } }; handler.postDelayed(runnable, 3000); handleCommand(intent); // new ClientThread().run(); return START_STICKY; } private void chose() { double x1, y1, x2, y2; Random rdr = new Random();// rdr为一组随机数流 Random rdz = new Random(); int Z = rdz.nextInt(360);// 随机数的生成范围小于360 double R2 = 1 + rdr.nextDouble() * 10;// x2街道 double R1 = 9 + rdr.nextDouble() * 20;// x1城镇 if (Z <= 90 && Z >= 0) { x1 = R1 * Math.sin(Z * Math.PI / 180);// (Z*Math.PI/180)为弧度制 y1 = R1 * Math.cos(Z * Math.PI / 180); x2 = R2 * Math.sin(Z * Math.PI / 180); y2 = R2 * Math.cos(Z * Math.PI / 180); } else if (Z <= 180 && Z > 90) { x1 = R1 * Math.cos((Z - 90) * Math.PI / 180); y1 = R1 * Math.sin((Z - 90) * Math.PI / 180) * -1; x2 = R2 * Math.cos((Z - 90) * Math.PI / 180); y2 = R2 * Math.sin((Z - 90) * Math.PI / 180) * -1; } else if (Z <= 270 && Z > 180) { x1 = R1 * Math.sin((Z - 180) * Math.PI / 180) * -1; y1 = R1 * Math.cos((Z - 180) * Math.PI / 180) * -1; x2 = R2 * Math.sin((Z - 180) * Math.PI / 180) * -1; y2 = R2 * Math.cos((Z - 180) * Math.PI / 180) * -1; } else { x1 = R1 * Math.cos((Z - 270) * Math.PI / 180) * -1; y1 = R1 * Math.sin((Z - 270) * Math.PI / 180); x2 = R2 * Math.cos((Z - 270) * Math.PI / 180) * -1; y2 = R2 * Math.sin((Z - 270) * Math.PI / 180); } Log.i("r", "R1=" + R1 + "R2=" + R2); Log.i("x1= y1=", "x1=" + x1 + "y1=" + y1);// 城镇 Log.i("x2= y2=", "x2=" + x2 + "y2=" + y2); // latitude=location.getLatitude();//精确 // longitude=location.getLongitude(); latitude1 = latitude + x1 / 111;// 城镇 longitude1 = longitude + y1 / (111 * Math.cos(Z * Math.PI / 180)); latitude2 = latitude + x2 / 111;// 街道 longitude2 = longitude + y2 / (111 * Math.cos(Z * Math.PI / 180)); // location1.setLatitude(latitude1);//城镇 // location1.setLongitude(longitude1); // // location2.setLatitude(latitude2);//街道 // location2.setLongitude(longitude2); // Log.d("test1111","哈哈"); if (user1.contains(AN) == true) {// 如果应用在用户城镇级 flag = 1; // Log.d("test222","哈哈"); } else { if (user2.contains(AN) == true) flag = 2;// 如果应用在用户街道级 else { if (user3.contains(AN) == true) flag = 3;// 如果应用在用户精确级 else { if (default1.contains(AN) == true) { Log.d("默认城镇级", "哈哈"); flag = 1; } else { if (default2.contains(AN) == true) { Log.d("默认街道级", "哈哈"); flag = 2; } else { if (default3.contains(AN) == true) { Log.d("默认精确级", "哈哈"); flag = 3; } else { flag = 0; } } } } } } } private LocationListener locationListener = new LocationListener() { // 位置发生改变时调用 @Override public void onLocationChanged(Location location) { Log.d("Location", "onLocationChanged"); // handler.removeCallbacks(runnable); } // provider失效时调用 @Override public void onProviderDisabled(String provider) { Log.d("Location", "onProviderdisabled"); } // provider启用时调用 @Override public void onProviderEnabled(String provider) { Log.d("Location", "onProviderEnabled"); Location.setLatitude(ltd_tmp); Location.setLongitude(lng_tmp); } // 状态改变时调用 @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.d("Location", "onStatusChanged"); Location.setLatitude(ltd_tmp); Location.setLongitude(lng_tmp); } }; void handleCommand(Intent intent) { if (service.ACTION_FOREGROUND.equals(intent.getAction())) { // In this sample, we'll use the same text for the ticker and the // expanded notification CharSequence text = getText(R.string.foreground_service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification( R.drawable.ic_launcher, text, System.currentTimeMillis()); // The PendingIntent to launch our activity if the user selects this // notification // 用户点击service的通知时返回到主界面 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, TownactivityActivity.class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent); startForeground(1000, notification); // startForegroundCompat(R.string.foreground_service_started, // notification); } else if (service.ACTION_BACKGROUND.equals(intent.getAction())) { stopForegroundCompat(R.string.foreground_service_started); } } public void onDestroy() { Log.i(TAG, "this is ondestroy"); handler.removeCallbacks(runnable); Toast.makeText(this, "service stopped", Toast.LENGTH_SHORT).show(); } public boolean onUnbind(Intent intent) { Log.i(TAG, "this is onUnbind"); return super.onUnbind(intent); } private void opDB() { // 清空所有元素 user1.clear(); user2.clear(); user3.clear(); default1.clear(); default2.clear(); default3.clear(); // Log.d("1","test"); Cursor tmp1 = DB.select("USER1"); Cursor tmp2 = DB.select("USER2"); Cursor tmp3 = DB.select("USER3"); // Log.d("1","test"); if (tmp1.moveToFirst() == false) ; else { String T1 = tmp1.getString(1); if (user1.contains(T1) == true) ; else user1.add(T1); while (tmp1.moveToNext()) { T1 = tmp1.getString(1); if (user1.contains(T1) == true) ; else user1.add(T1); // Log.d("test",T1); } } if (tmp2.moveToFirst() == false) ; else { String T2 = tmp2.getString(1); if (user2.contains(T2) == true) ; else user2.add(T2); while (tmp2.moveToNext()) { T2 = tmp2.getString(1); if (user2.contains(T2) == true) ; else user2.add(T2); // Log.d("test",T2); } } if (tmp3.moveToFirst() == false) ; else { String T3 = tmp3.getString(1); if (user3.contains(T3) == true) ; else user3.add(T3); while (tmp3.moveToNext()) { T3 = tmp3.getString(1); if (user3.contains(T3) == true) ; else user3.add(T3); // Log.d("test",T3); } } } }
关于iterator的成员遍历问题
我写了服务器端和客户端的程序,我想是实现客户之间发送群组消息,所以我在服务器端定义全局变量在线组员集合,然后在服务器主类构造方法实例化了在线组员集合,然后定义一个群组消息发送方法,但是发现遍历不成功,跳出了while语句,it.hasNext()竟然为false 客户端的代码应该是没问题的,就是 使用使用线程去接收服务器端的消息 新人一枚 求求大神指教一下 代码如下 public class GroupServer { private static Set<Socket> Members; private int port=8008; private ServerSocket serverSocket; private ExecutorService executorService; //线程池 private final int POOL_SIZE=15; //单个CPU时线程池中工作线程的数目 public GroupServer() throws IOException { serverSocket = new ServerSocket(port);//打开服务器端口 //创建线程池 //Runtime的availableProcessors()方法返回当前系统的CPU的数目 //系统的CPU越多,线程池中工作线程的数目也应该越多 executorService= Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * POOL_SIZE); Members=new HashSet<Socket> (); System.out.println("多用户服务器启动"); } public void service() { while (true) { Socket socket=null; try { socket = serverSocket.accept(); //监听客户请求, 阻塞语句. //接受一个客户请求,从线程池中拿出一个线程专门处理该客户. executorService.execute(new Handler(socket)); }catch (IOException e) { } } } public static void sendToAllMembers(String msg)throws IOException{ PrintWriter pw; Socket tempSocket; OutputStream out; Iterator it=Members.iterator(); while(it.hasNext()){//遍历在线成员set集合. System.out.println("socketTCP.GroupServer.sendToAllMembers()"); tempSocket=(Socket) it.next(); //取出一个成员 out =tempSocket.getOutputStream();//得到输出流 //装饰成字符流 pw=new PrintWriter(new OutputStreamWriter(out,"GB2312"),true); System.out.println("socketTCP.GroupServer.sendToAllMembers()"); pw.println(msg);//发送聊天信息给成员 }//end while群组发送结束。 } public static void removeMember(Socket socket){ Members.remove(socket);//删除一个成员 } class Handler implements Runnable{ private Socket socket; public Handler(Socket socket){ this.socket=socket; } private PrintWriter getWriter(Socket socket)throws IOException{ OutputStream socketOut = socket.getOutputStream(); return new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true); } private BufferedReader getReader(Socket socket)throws IOException{ InputStream socketIn = socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn,"GB2312")); } public void run(){//覆盖线程体 try { System.out.println("New connection accepted " +socket.getInetAddress()); BufferedReader br =getReader(socket);//字节装饰成字符流 PrintWriter pw = getWriter(socket); //字节装饰成字符流 String msg = null; while ((msg = br.readLine()) != null) { sendToAllMembers(msg); pw.println("From ThreadServer: "+msg);//send to client. if (msg.contains("bye".subSequence(0, 2))){ System.out.println( socket.getInetAddress() + ":" +"Exit"); break; } } }catch (IOException e) { e.printStackTrace(); }finally { try{ if(socket!=null)socket.close(); }catch (IOException e) { } } } } public static void main(String args[])throws IOException { new GroupServer().service(); } }
Servlet实现排队处理视频转换请求中的疑问,贴代码请斧正!
项目需求:客户端上传视频(*.avi),server将请求排队,然后一个一个排队处理转换任务. 前面问过该问题,现在自己实现,由于多线程不精通. 如下实现该排队需求,自己感觉不太准确,有问题,请指出,并给个解决方法. (tip,没有servlet的单线程模式或将dopost方法synchronied,视乎这样做是由系统将请求排队,request请求不能立即得到回复! :) ) 1.TaskBean 写了一个bean,这个bean用来存储了转换任务的属性. [code="java"]package videoconvert; public class TaskBean { private String videoPath; private String flvPath; private boolean isConverting; public String getVideoPath() { return videoPath; } public void setVideoPath(String videoPath) { this.videoPath = videoPath; } public String getFlvPath() { return flvPath; } public void setFlvPath(String flvPath) { this.flvPath = flvPath; } public boolean getIsConverting() { return isConverting; } public void setIsConverting(boolean isConverting) { this.isConverting = isConverting; } }[/code] 2.VideoConvert 这是个servlet,用来排队请求,并调度转换工具进行转换. [code="java"]package videoconvert; import java.io.IOException; import java.io.PrintWriter; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class VideoConvert extends HttpServlet { private static final long serialVersionUID = 6312986385178354217L; private static Logger logger = LoggerFactory.getLogger(VideoConvert.class); private static LinkedList<TaskBean> taskStack = new LinkedList<TaskBean>(); public VideoConvert() { super(); } @Override public void init() throws ServletException { // TODO Auto-generated method stub super.init(); new Timer().schedule(new TimerTask() { public void run() { checkTaskList();[color=red]//这里按时间间隔检查栈.并取出task来执行.[/color] } }, 0, 10000); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (request.getRemoteAddr().equals("127.0.0.1")) { TaskBean task = new TaskBean(); String videoPath = (String) request.getAttribute("VideoPath"); String flvPath = (String) request.getAttribute("FlvPath"); if (null != videoPath && null != flvPath) { task.setVideoPath(videoPath); task.setFlvPath(flvPath); task.setIsConverting(false); synchronized (taskStack) { [color=red] //多线程以taskStack栈作为同步量,当持有taskStack对象才添加任务进栈[/color] taskStack.addLast(task); logger.info("add task to queue!"); } } else { logger.info("the paramters are null!"); } } else { logger.info("visit is illegal!"); } response.setContentType("text/html; charset=UTF-8"); PrintWriter pw = response.getWriter(); pw.write("上传视频成功,等待转换....") pw.flush(); } //这个是timer触发的任务,取出stack中的一个任务,然后检查是否在转换中,如果没有就调用工具进行转换. private void checkTaskList() { synchronized (taskStack) { [color=red]//这里感觉不准确,因为同步块里面,Timer新建的了一个线程p1来调用外 //部工具 // FFmpeg.并且会(process.waitFor();)等待FFmepg运行完成来返回结果. 所以在调 // 用外部工具的整个过程都占用了同步量(taskStack).所以应该如何改进...[/color] TaskBean task = taskStack.peekFirst(); if (null != task) { if (!task.getIsConverting()) { task.setIsConverting(true); executProcess(task); } } } } private void executProcess(TaskBean task) { MediaUtility mu = new MediaUtility(); //在类MediaUtility 中调用新建线程调用工具,并waitfor()结果 if (mu.video2Flv(task.getVideoPath(), task.getFlvPath())) { taskStack.removeFirst(); logger.info("achieve video convert,removeFirst task!"); } else { logger.error("video convert fail!"); taskStack.removeFirst(); } } }[/code] 3.调用工具的类 MediaUtility [code="java"]package videoconvert; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MediaUtility { private static Logger logger = LoggerFactory.getLogger(MediaUtility.class); public boolean video2Flv(String videoPath, String flvPath) { if (!checkfile(videoPath)) { logger.error(videoPath + " is not file!"); return false; } String cmdStr = "ffmpeg -i " + videoPath + " " + flvPath; logger.info(cmdStr); logger.info("Starting convert video to flv...."); BufferedReader ffmpegOut = null; try { Process process = Runtime.getRuntime().exec(cmdStr); // ffmpegOut = new BufferedReader(new InputStreamReader(process // .getInputStream())); ffmpegOut = new BufferedReader(new InputStreamReader(process .getErrorStream())); // FileWriter fileOut = new FileWriter(new File("c:/F.txt")); String dLine = ""; while ((dLine = ffmpegOut.readLine()) != null) { logger.info(dLine); // fileOut.write(dLine); } // fileOut.close(); process.waitFor(); logger.info("***************************** end convert video *************************"); ffmpegOut.close(); return true; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } finally { try { if (null != ffmpegOut) { ffmpegOut.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static boolean checkfile(String path) { File file = new File(path); if (!file.isFile()) { return false; } return true; } // public static void main(String[] args) { // boolean bb = video2Flv("d:/ffmpeg/uploadVideo/Video1.wmv", // "d:/ffmpeg/convertedVideo/pp1.flv"); // logger.info("the bb result is " + bb); // boolean cc = video2Flv("d:/ffmpeg/uploadVideo/Video2.wmv", // "d:/ffmpeg/convertedVideo/pp2.flv"); // logger.info("the cc result is " + cc); // }[/code] 如上面的代码.上面的代码每次只能有一个视频在转换,如果想改进为最多同时有3个或者6个任务在执行呢? 此时是否要再设置一个信号量呢? [b]问题补充:[/b] [quote]放一个线程池(ThreadPool),可以解决你的问题,每次把你的任务丢到线程池里面。[/quote] 只知道连接数据库用到线程池.请求排队也可以用线程池?有这样的应用吗? 8) 并且具体如何用,能给个例子吗? [b]问题补充:[/b] [quote]jdk的cocurrent里面有现成的。 Java代码 queue = new LinkedBlockingQueue<Runnable>(1000); threadPool = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, queue); 这样就定义了一个线程池。 Java代码 threadPool.execute(runnable); 这样就放入线程池一个Runnable了,就可以满足你的需求了。[/quote] 感谢taopian的热心回复,马上看jdk的cocurrent. :) [b]问题补充:[/b] [quote]jdk的cocurrent里面有现成的。 [/quote] 谢谢了,cocurrent包,感觉很好,应该就是解决问题的办法了. :idea: 另外,我还有一个不好很明白,就是 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) 构造函数中的 BlockingQueue<Runnable> workQueue的作用? 感觉JVM可以在内部维护这个队列,不用释放出接口来. 当然尽管API上讲了" 大队列 用小池, 小队列 用大池," 可以提高资源利用率.然而现在还不是很理解.后面在实践中体会了. 嘿嘿 [b]问题补充:[/b] 先问再吃饭. :D [quote]BlockingQueue<Runnable> workQueue 这个就是放一个队列,任务扔到队列里面,可以对并发做控制。 把这个队列暴露出来,能够让你进行很好的控制,并且你可以继承BlockingQueue,来加入你自己需要的功能,:)。[/quote] 嗯,是的,可以自己继承BlockingQueue,再增加一些自己的功能,然后放入executor中去. 面向接口 :) 现在我已经可以顺利,并准确的运行了. 最后一个疑问: executor.excute(new Runnable(){ public void run(){ run 中的变量要求是final的.final变量的GC时间是否会有影响呢? 或者有别的更好解决方法 } } ) 我是这样的改的: 这个bean被迫为final的了.呵呵,有更好的方法吗? [code="java"]if (null != videoPath && null != flvPath) { final TaskBean task = new TaskBean(); task.setVideoPath(videoPath); task.setFlvPath(flvPath); threadPool.execute(new Runnable(){ public void run(){ MediaUtility.video2Flv(task.getVideoPath(), task.getFlvPath()); } });[/code] 哎呀,罗嗦了,吃饭先..... :D
condition.await()并发问题
public class BlockArrayList<E> extends ArrayList<E> { /** * long serialVersionUID:TODO(用一句话描述这个变量表示什么) * * @since 1.0.0 */ private static final long serialVersionUID = 1L; private ReentrantLock lock = new ReentrantLock(); private Condition notEmpty = lock.newCondition(); public int i = 0; public Exception ee; public E take() throws InterruptedException { try { lock.lock(); E e = null; int size = this.size(); if(size == 0) { notEmpty.await(); } i++; System.out.println(i); try { e = this.remove(0); } catch(Exception e1) { ee = e1; } return e; } finally { lock.unlock(); } } public boolean offer(E e) { try { lock.lock(); this.add(e); notEmpty.signal(); return true; } finally { lock.unlock(); } } public void op() { E s = null; try { s = this.take(); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() +" 被动结束"); e.printStackTrace(); } } public class MyThreadFactory implements ThreadFactory { private AtomicInteger NUMBER = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setName("shaoweiThread-"+NUMBER.decrementAndGet()); return t; } } public static void main(String[] args) { final BlockArrayList<String> list = new BlockArrayList<String>(); ThreadFactory threadThread = list.new MyThreadFactory(); Thread t = threadThread.newThread(new Runnable() { @Override public void run() { int i = 0; while(i <410000) { list.op(); } } }); t.start(); threadThread.newThread(new Runnable() { @Override public void run() { int i = 0; while(i <410000) { list.op(); } } }).start(); threadThread.newThread(new Runnable() { @Override public void run() { for(int i=0;i<400000;i++) { boolean flag = list.offer("item" + i); if(!flag) { System.out.println("添加元素失败"); } } System.out.println(list.ee); } }).start(); System.out.println("主线程结束"); } } 多个线程去取阻塞队列为啥会有并发问题呢?i正常应该为400000的,谁能给解释下
今天看JDK的一些原码,头都大了。。。
<pre name="code" class="java"> public interface Iterator&lt;E&gt; { boolean hasNext(); //是否有下一个元素 E next(); //下一个元素 void remove(); //删除 } public interface Collection&lt;E&gt; extends Iterable&lt;E&gt; { int size(); //包函的元素 boolean isEmpty(); //是否为空 boolean contains(Object o); //是否包括o Iterator&lt;E&gt; iterator(); //生成Iterator对象 Object[] toArray(); //生成数组对象 &lt;T&gt; T[] toArray(T[] a); // boolean add(E o); //加一个对象 boolean remove(Object o); //删除一个对象 boolean containsAll(Collection&lt;?&gt; c); // boolean addAll(Collection&lt;? extends E&gt; c); //添加所有的到当前集合,包括extends E的 boolean removeAll(Collection&lt;?&gt; c); // boolean retainAll(Collection&lt;?&gt; c); // void clear(); //清除 boolean equals(Object o); // int hashCode(); // } public interface List&lt;E&gt; extends Collection&lt;E&gt; { int size(); boolean isEmpty(); boolean contains(Object o); Iterator&lt;E&gt; iterator(); Object[] toArray(); &lt;T&gt; T[] toArray(T[] a); boolean add(E o); boolean remove(Object o); boolean containsAll(Collection&lt;?&gt; c); boolean addAll(Collection&lt;? extends E&gt; c); boolean addAll(int index, Collection&lt;? extends E&gt; c); boolean removeAll(Collection&lt;?&gt; c); boolean retainAll(Collection&lt;?&gt; c); void clear(); boolean equals(Object o); int hashCode(); //List接口里面自己的方法 E get(int index); //根据index值出相应的对象 E set(int index, E element); //设置相应位置的对象 void add(int index, E element); //增加相应位置的对象 E remove(int index); //删除 int indexOf(Object o); //根据对象获得相应对象的位置,没有找到应该会是-1 int lastIndexOf(Object o); //是最后一个开始找吧(不知道) ListIterator&lt;E&gt; listIterator(); //成生ListIterator对象,链表实现的吧 ListIterator&lt;E&gt; listIterator(int index); //成生ListIterator对象,从index开始生成 List&lt;E&gt; subList(int fromIndex, int toIndex); //从fromIndex到toIndex生成新的List对象 } public class ArrayList&lt;E&gt; extends AbstractList&lt;E&gt; implements List&lt;E&gt;, RandomAccess, Cloneable, java.io.Serializable{ private static final long serialVersionUID = 8683452581122892189L; //我不知道为什么会有一个这样的变量 private transient E[] elementData; //用来保存E的数组,ArrayList是数组实现的 private int size; //指这个数组保存的个数,并不是数组的大小 private int modCount; //构造方法 public ArrayList(int initialCapacity) { super(); if (initialCapacity &lt; 0){ throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); } this.elementData = (E[])new Object[initialCapacity]; } public ArrayList() { this(10); } public ArrayList(Collection&lt;? extends E&gt; c) { size = c.size(); // Allow 10% room for growth int capacity = (int)Math.min((size*110L)/100, Integer.MAX_VALUE); elementData = (E[])c.toArray(new Object[capacity]); } /** * 看数组里面的元素和数组本身的长度,如果size&lt;length就可以缩小 * */ public void trimToSize() { modCount++; //这个到底是干什么用的? int oldCapacity = elementData.length; if (size &lt; oldCapacity) { Object oldData[] = elementData; elementData = (E[])new Object[size]; System.arraycopy(oldData, 0, elementData, 0, size); } } //扩大容量 public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity &gt; oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; //JDK1.5是这样写的哦,不知道为什么? if (newCapacity &lt; minCapacity){ newCapacity = minCapacity; //他的容量并一定扩大到minCapacity,满足条件才会扩大到那样 } elementData = (E[])new Object[newCapacity]; System.arraycopy(oldData, 0, elementData, 0, size); } } public int size() { return size; } public boolean isEmpty() { return size == 0; } //查个某个对象在数组中的位置,是否相于根据对象的equals方法 public int indexOf(Object elem) { if (elem == null) { for (int i = 0; i &lt; size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i &lt; size; i++) if (elem.equals(elementData[i])) return i; } return -1; } //这个方法和上面一个意思 public boolean contains(Object elem) { return indexOf(elem) &gt;= 0; } //很明显这个方法是从后向前找的 public int lastIndexOf(Object elem) { if (elem == null) { for (int i = size-1; i &gt;= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i &gt;= 0; i--) if (elem.equals(elementData[i])) return i; } return -1; } //克隆 //先复制这个对象,再复制这个对象中数组对象 public Object clone() { try { ArrayList&lt;E&gt; v = (ArrayList&lt;E&gt;) super.clone(); v.elementData = (E[])new Object[size]; System.arraycopy(elementData, 0, v.elementData, 0, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } public Object[] toArray() { Object[] result = new Object[size]; System.arraycopy(elementData, 0, result, 0, size); return result; } //不知道什么意思。。。。 public &lt;T&gt; T[] toArray(T[] a) { if (a.length &lt; size){ a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); } System.arraycopy(elementData, 0, a, 0, size); if (a.length &gt; size){ a[size] = null; } return a; } //获得 public E get(int index) { RangeCheck(index); //看是否超出size的大小 return elementData[index]; } //设置 public E set(int index, E element) { RangeCheck(index); E oldValue = elementData[index]; elementData[index] = element; return oldValue; } //增加一个对象 public boolean add(E o) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = o; return true; } //在index这个位置后面加个对象进去 public void add(int index, E element) { if (index &gt; size || index &lt; 0){ throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); } ensureCapacity(size+1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } public E remove(int index) { RangeCheck(index); modCount++; E oldValue = elementData[index]; int numMoved = size - index - 1; if (numMoved &gt; 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; } public boolean remove(Object o) { if (o == null) { for (int index = 0; index &lt; size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index &lt; size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } //private方法了 private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved &gt; 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work } public void clear() { modCount++; // Let gc do its work for (int i = 0; i &lt; size; i++){ elementData[i] = null; } size = 0; } public boolean addAll(Collection&lt;? extends E&gt; c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacity(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; } public boolean addAll(int index, Collection&lt;? extends E&gt; c) { if (index &gt; size || index &lt; 0) throw new IndexOutOfBoundsException( "Index: " + index + ", Size: " + size); Object[] a = c.toArray(); int numNew = a.length; ensureCapacity(size + numNew); // Increments modCount int numMoved = size - index; if (numMoved &gt; 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } protected void removeRange(int fromIndex, int toIndex) { modCount++; int numMoved = size - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); // Let gc do its work int newSize = size - (toIndex-fromIndex); while (size != newSize){ elementData[--size] = null; } } private void RangeCheck(int index) { if (index &gt;= size){ throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); } } private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException{ int expectedModCount = modCount; // Write out element count, and any hidden stuff s.defaultWriteObject(); // Write out array length s.writeInt(elementData.length); // Write out all elements in the proper order. for (int i=0; i&lt;size; i++){ s.writeObject(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in size, and any hidden stuff s.defaultReadObject(); // Read in array length and allocate array int arrayLength = s.readInt(); Object[] a = elementData = (E[])new Object[arrayLength]; // Read in all elements in the proper order. for (int i=0; i&lt;size; i++){ a[i] = s.readObject(); } } } public class Vector&lt;E&gt; extends AbstractList&lt;E&gt; implements List&lt;E&gt;, RandomAccess, Cloneable, java.io.Serializable{ protected Object[] elementData; protected int elementCount; protected int capacityIncrement; public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity &lt; 0){ throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); } this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; } public Vector(int initialCapacity) { this(initialCapacity, 0); } public Vector() { this(10); } public Vector(Collection&lt;? extends E&gt; c) { elementCount = c.size(); // 10% for growth elementData = new Object[(int)Math.min((elementCount*110L)/100,Integer.MAX_VALUE)]; c.toArray(elementData); } //把这个Vector对象的数组复制到别一个去 public synchronized void copyInto(Object[] anArray) { System.arraycopy(elementData, 0, anArray, 0, elementCount); } public synchronized void trimToSize() { modCount++; int oldCapacity = elementData.length; if (elementCount &lt; oldCapacity) { Object oldData[] = elementData; elementData = new Object[elementCount]; System.arraycopy(oldData, 0, elementData, 0, elementCount); } } public synchronized void ensureCapacity(int minCapacity) { modCount++; ensureCapacityHelper(minCapacity); } private void ensureCapacityHelper(int minCapacity) { int oldCapacity = elementData.length; if (minCapacity &gt; oldCapacity) { Object[] oldData = elementData; int newCapacity = (capacityIncrement &gt; 0)?(oldCapacity+capacityIncrement):(oldCapacity*2); if (newCapacity &lt; minCapacity) { newCapacity = minCapacity; } elementData = new Object[newCapacity]; System.arraycopy(oldData, 0, elementData, 0, elementCount); } } public synchronized void setSize(int newSize) { modCount++; if (newSize &gt; elementCount) { ensureCapacityHelper(newSize); } else { for (int i = newSize ; i &lt; elementCount ; i++) { elementData[i] = null; } } elementCount = newSize; } public synchronized int capacity() { return elementData.length; } public synchronized int size() { return elementCount; } public synchronized boolean isEmpty() { return elementCount == 0; } public Enumeration&lt;E&gt; elements() { return new Enumeration&lt;E&gt;() { int count = 0; public boolean hasMoreElements() { return count &lt; elementCount; } public E nextElement() { synchronized (Vector.this) { if (count &lt; elementCount) { return (E)elementData[count++]; } } throw new NoSuchElementException("Vector Enumeration"); } }; } public boolean contains(Object elem) { return indexOf(elem, 0) &gt;= 0; } public int indexOf(Object elem) { return indexOf(elem, 0); } public synchronized int indexOf(Object elem, int index) { if (elem == null) { for (int i = index ; i &lt; elementCount ; i++) if (elementData[i]==null) return i; } else { for (int i = index ; i &lt; elementCount ; i++) if (elem.equals(elementData[i])) return i; } return -1; } public synchronized int lastIndexOf(Object elem) { return lastIndexOf(elem, elementCount-1); } public synchronized int lastIndexOf(Object elem, int index) { if (index &gt;= elementCount) throw new IndexOutOfBoundsException(index + " &gt;= "+ elementCount); if (elem == null) { for (int i = index; i &gt;= 0; i--) if (elementData[i]==null) return i; } else { for (int i = index; i &gt;= 0; i--) if (elem.equals(elementData[i])) return i; } return -1; } public synchronized E elementAt(int index) { if (index &gt;= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " &gt;= " + elementCount); } return (E)elementData[index]; } //........................................ } public class Stack&lt;E&gt; extends Vector&lt;E&gt; { public Stack() { } public E push(E item) { addElement(item); //父类的方法 return item; } public synchronized E pop() { E obj; int len = size(); obj = peek(); removeElementAt(len - 1); return obj; } public synchronized E peek() { int len = size(); if (len == 0) throw new EmptyStackException(); return elementAt(len - 1); } public boolean empty() { return size() == 0; } public synchronized int search(Object o) { int i = lastIndexOf(o); if (i &gt;= 0) { return size() - i; } return -1; } } </pre><br /><strong>问题补充:</strong><br />写得不错呀,几个模式和线程同步都到的,有啥问题吗? <br />============================================= <br />这是JDK的源码,用到什么模式了啊,说一说啥<br /><strong>问题补充:</strong><br />哇,你太猛了,你知道怎么去看JDK的原代码么?那么多,没有方法是看不下去的哦。。。 <br /><br /><strong>问题补充:</strong><br />那你介绍几本书哦,我想把J2SE的基础搞的好一点。。 <br />我现在看的是Thanking Java 不过是讲的1.1版本的,看了两百多页就没有看下去了 <br />还在看的是数据结构(JAVA写的)........ <br />看了数据结构里面的链表才来看JDK里面的原码的,我以前就知道用,不知道里面是写的啥。。。
程序员必须掌握的核心算法有哪些?
由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我,数据结构与算法应该要学习到哪个程度呢?,说实话,这个问题我不知道要怎么回答你,主要取决于你想学习到哪些程度,不过针对这个问题,我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法。这些算法与数据结构的学习大多数是零散的,并没有一本把他们全部覆盖的书籍。下面是我觉得值得学习的一些算法以及数据结构,当然,我也会整理一些看过...
大学四年自学走来,这些私藏的实用工具/学习网站我贡献出来了
大学四年,看课本是不可能一直看课本的了,对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。主要有:电子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站。 注意:文中提到的所有资源,文末我都给你整理好了,你们只管拿去,如果觉得不错,转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...
卸载 x 雷某度!GitHub 标星 1.5w+,从此我只用这款全能高速下载工具!
作者 | Rocky0429 来源 | Python空间 大家好,我是 Rocky0429,一个喜欢在网上收集各种资源的蒟蒻… 网上资源眼花缭乱,下载的方式也同样千奇百怪,比如 BT 下载,磁力链接,网盘资源等等等等,下个资源可真不容易,不一样的方式要用不同的下载软件,因此某比较有名的 x 雷和某度网盘成了我经常使用的工具。 作为一个没有钱的穷鬼,某度网盘几十 kb 的下载速度让我...
2019年还剩1天,我从外包公司离职了
这日子过的可真快啊,2019年还剩1天,外包公司干了不到3个月,我离职了
《面试宝典》2019年springmvc面试高频题(java)
前言 2019即将过去,伴随我们即将迎来的又是新的一年,过完春节,马上又要迎来新的金三银四面试季。那么,作为程序猿的你,是否真的有所准备的呢,亦或是安于本职工作,继续做好手头上的事情。 当然,不论选择如何,假如你真的准备在之后的金三银四跳槽的话,那么作为一个Java工程师,就不可不看了。如何在几个月的时间里,快速的为即将到来的面试进行充分的准备呢? 1、什么是Spring MVC ?简单...
计算机网络的核心概念
这是《计算机网络》系列文章的第二篇文章 我们第一篇文章讲述了计算机网络的基本概念,互联网的基本名词,什么是协议以及几种接入网以及网络传输的物理媒体,那么本篇文章我们来探讨一下网络核心、交换网络、时延、丢包、吞吐量以及计算机网络的协议层次和网络攻击。 网络核心 网络的核心是由因特网端系统和链路构成的网状网络,下面这幅图正确的表达了这一点 那么在不同的 ISP 和本地以及家庭网络是如何交换信息的呢?...
python自动下载图片
近日闲来无事,总有一种无形的力量萦绕在朕身边,让朕精神涣散,昏昏欲睡。 可是,像朕这么有职业操守的社畜怎么能在上班期间睡瞌睡呢,我不禁陷入了沉思。。。。 突然旁边的IOS同事问:‘嘿,兄弟,我发现一个网站的图片很有意思啊,能不能帮我保存下来提升我的开发灵感?’ 作为一个坚强的社畜怎么能说自己不行呢,当时朕就不假思索的答应:‘oh, It’s simple. Wait for me a few
一名大专同学的四个问题
【前言】   收到一封来信,赶上各种事情拖了几日,利用今天要放下工作的时机,做个回复。   2020年到了,就以这一封信,作为开年标志吧。 【正文】   您好,我是一名现在有很多困惑的大二学生。有一些问题想要向您请教。   先说一下我的基本情况,高考失利,不想复读,来到广州一所大专读计算机应用技术专业。学校是偏艺术类的,计算机专业没有实验室更不用说工作室了。而且学校的学风也不好。但我很想在计算机领...
复习一周,京东+百度一面,不小心都拿了Offer
京东和百度一面都问了啥,面试官百般刁难,可惜我全会。
20道你必须要背会的微服务面试题,面试一定会被问到
写在前面: 在学习springcloud之前大家一定要先了解下,常见的面试题有那块,然后我们带着问题去学习这个微服务技术,那么就会更加理解springcloud技术。如果你已经学了springcloud,那么在准备面试的时候,一定要看看看这些面试题。 文章目录1、什么是微服务?2、微服务之间是如何通讯的?3、springcloud 与dubbo有哪些区别?4、请谈谈对SpringBoot 和S...
Java 14 都快来了,为什么还有这么多人固守Java 8?
从Java 9开始,Java版本的发布就让人眼花缭乱了。每隔6个月,都会冒出一个新版本出来,Java 10 , Java 11, Java 12, Java 13, 到2020年3月份,...
轻松搭建基于 SpringBoot + Vue 的 Web 商城应用
首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API ...
Python+OpenCV实时图像处理
目录 1、导入库文件 2、设计GUI 3、调用摄像头 4、实时图像处理 4.1、阈值二值化 4.2、边缘检测 4.3、轮廓检测 4.4、高斯滤波 4.5、色彩转换 4.6、调节对比度 5、退出系统 初学OpenCV图像处理的小伙伴肯定对什么高斯函数、滤波处理、阈值二值化等特性非常头疼,这里给各位分享一个小项目,可通过摄像头实时动态查看各类图像处理的特点,也可对各位调参、测试...
2020年一线城市程序员工资大调查
人才需求 一线城市共发布岗位38115个,招聘120827人。 其中 beijing 22805 guangzhou 25081 shanghai 39614 shenzhen 33327 工资分布 2020年中国一线城市程序员的平均工资为16285元,工资中位数为14583元,其中95%的人的工资位于5000到20000元之间。 和往年数据比较: yea...
为什么猝死的都是程序员,基本上不见产品经理猝死呢?
相信大家时不时听到程序员猝死的消息,但是基本上听不到产品经理猝死的消息,这是为什么呢? 我们先百度搜一下:程序员猝死,出现将近700多万条搜索结果: 搜索一下:产品经理猝死,只有400万条的搜索结果,从搜索结果数量上来看,程序员猝死的搜索结果就比产品经理猝死的搜索结果高了一倍,而且从下图可以看到,首页里面的五条搜索结果,其实只有两条才是符合条件。 所以程序员猝死的概率真的比产品经理大,并不是错...
害怕面试被问HashMap?这一篇就搞定了!
声明:本文以jdk1.8为主! 搞定HashMap 作为一个Java从业者,面试的时候肯定会被问到过HashMap,因为对于HashMap来说,可以说是Java集合中的精髓了,如果你觉得自己对它掌握的还不够好,我想今天这篇文章会非常适合你,至少,看了今天这篇文章,以后不怕面试被问HashMap了 其实在我学习HashMap的过程中,我个人觉得HashMap还是挺复杂的,如果真的想把它搞得明明白...
毕业5年,我问遍了身边的大佬,总结了他们的学习方法
我问了身边10个大佬,总结了他们的学习方法,原来成功都是有迹可循的。
python爬取百部电影数据,我分析出了一个残酷的真相
2019年就这么匆匆过去了,就在前几天国家电影局发布了2019年中国电影市场数据,数据显示去年总票房为642.66亿元,同比增长5.4%;国产电影总票房411.75亿元,同比增长8.65%,市场占比 64.07%;城市院线观影人次17.27亿,同比增长0.64%。 看上去似乎是一片大好对不对?不过作为一名严谨求实的数据分析师,我从官方数据中看出了一点端倪:国产票房增幅都已经高达8.65%了,为什...
推荐10个堪称神器的学习网站
每天都会收到很多读者的私信,问我:“二哥,有什么推荐的学习网站吗?最近很浮躁,手头的一些网站都看烦了,想看看二哥这里有什么新鲜货。” 今天一早做了个恶梦,梦到被老板辞退了。虽然说在我们公司,只有我辞退老板的份,没有老板辞退我这一说,但是还是被吓得 4 点多都起来了。(主要是因为我掌握着公司所有的核心源码,哈哈哈) 既然 4 点多起来,就得好好利用起来。于是我就挑选了 10 个堪称神器的学习网站,推...
这些软件太强了,Windows必装!尤其程序员!
Windows可谓是大多数人的生产力工具,集娱乐办公于一体,虽然在程序员这个群体中都说苹果是信仰,但是大部分不都是从Windows过来的,而且现在依然有很多的程序员用Windows。 所以,今天我就把我私藏的Windows必装的软件分享给大家,如果有一个你没有用过甚至没有听过,那你就赚了????,这可都是提升你幸福感的高效率生产力工具哦! 走起!???? NO、1 ScreenToGif 屏幕,摄像头和白板...
阿里面试一个ArrayList我都能跟面试官扯半小时
我是真的没想到,面试官会这样问我ArrayList。
曾经优秀的人,怎么就突然不优秀了。
职场上有很多辛酸事,很多合伙人出局的故事,很多技术骨干被裁员的故事。说来模板都类似,曾经是名校毕业,曾经是优秀员工,曾经被领导表扬,曾经业绩突出,然而突然有一天,因为种种原因,被裁员了,...
大学四年因为知道了这32个网站,我成了别人眼中的大神!
依稀记得,毕业那天,我们导员发给我毕业证的时候对我说“你可是咱们系的风云人物啊”,哎呀,别提当时多开心啦????,嗯,我们导员是所有导员中最帅的一个,真的???? 不过,导员说的是实话,很多人都叫我大神的,为啥,因为我知道这32个网站啊,你说强不强????,这次是绝对的干货,看好啦,走起来! PS:每个网站都是学计算机混互联网必须知道的,真的牛杯,我就不过多介绍了,大家自行探索,觉得没用的,尽管留言吐槽吧???? 社...
2020年1月中国编程语言排行榜,python是2019增长最快编程语言
编程语言比例 排名 编程语言 最低工资 工资中位数 最低工资 最高工资 人头 人头百分比 1 rust 20713 17500 5042 46250 480 0.14% 2 typescript 18503 22500 6000 30000 1821 0.52% 3 lua 18150 17500 5250 35000 2956 0.84% 4 go 17989 16...
看完这篇HTTP,跟面试官扯皮就没问题了
我是一名程序员,我的主要编程语言是 Java,我更是一名 Web 开发人员,所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶,看完让你有一种恍然大悟、醍醐灌顶的感觉。 最初在有网络之前,我们的电脑都是单机的,单机系统是孤立的,我还记得 05 年前那会儿家里有个电脑,想打电脑游戏还得两个人在一个电脑上玩儿,及其不方便。我就想为什么家里人不让上网,我的同学 xxx 家里有网,每...
史上最全的IDEA快捷键总结
现在Idea成了主流开发工具,这篇博客对其使用的快捷键做了总结,希望对大家的开发工作有所帮助。
阿里程序员写了一个新手都写不出的低级bug,被骂惨了。
这种新手都不会范的错,居然被一个工作好几年的小伙子写出来,差点被当场开除了。
谁是华为扫地僧?
是的,华为也有扫地僧!2020年2月11-12日,“养在深闺人不知”的华为2012实验室扫地僧们,将在华为开发者大会2020(Cloud)上,和大家见面。到时,你可以和扫地僧们,吃一个洋...
Idea 中最常用的10款插件(提高开发效率),一定要学会使用!
学习使用一些插件,可以提高开发效率。对于我们开发人员很有帮助。这篇博客介绍了开发中使用的插件。
AI 没让人类失业,搞 AI 的人先失业了
最近和几个 AI 领域的大佬闲聊 根据他们讲的消息和段子 改编出下面这个故事 如有雷同 都是巧合 1. 老王创业失败,被限制高消费 “这里写我跑路的消息实在太夸张了。” 王葱葱哼笑一下,把消息分享给群里。 阿杰也看了消息,笑了笑。在座几位也都笑了。 王葱葱是个有名的人物,21岁那年以全额奖学金进入 KMU 攻读人工智能博士,累计发表论文 40 余篇,个人技术博客更是成为深度学习领域内风向标。 ...
2020年,冯唐49岁:我给20、30岁IT职场年轻人的建议
点击“技术领导力”关注∆每天早上8:30推送 作者|Mr.K 编辑| Emma 来源|技术领导力(ID:jishulingdaoli) 前天的推文《冯唐:职场人35岁以后,方法论比经验重要》,收到了不少读者的反馈,觉得挺受启发。其实,冯唐写了不少关于职场方面的文章,都挺不错的。可惜大家只记住了“春风十里不如你”、“如何避免成为油腻腻的中年人”等不那么正经的文章。 本文整理了冯...
作为一名大学生,如何在B站上快乐的学习?
B站是个宝,谁用谁知道???? 作为一名大学生,你必须掌握的一项能力就是自学能力,很多看起来很牛X的人,你可以了解下,人家私底下一定是花大量的时间自学的,你可能会说,我也想学习啊,可是嘞,该学习啥嘞,不怕告诉你,互联网时代,最不缺的就是学习资源,最宝贵的是啥? 你可能会说是时间,不,不是时间,而是你的注意力,懂了吧! 那么,你说学习资源多,我咋不知道,那今天我就告诉你一个你必须知道的学习的地方,人称...
那些年,我们信了课本里的那些鬼话
教材永远都是有错误的,从小学到大学,我们不断的学习了很多错误知识。 斑羚飞渡 在我们学习的很多小学课文里,有很多是错误文章,或者说是假课文。像《斑羚飞渡》: 随着镰刀头羊的那声吼叫,整个斑羚群迅速分成两拨,老年斑羚为一拨,年轻斑羚为一拨。 就在这时,我看见,从那拨老斑羚里走出一只公斑羚来。公斑羚朝那拨年轻斑羚示意性地咩了一声,一只半大的斑羚应声走了出来。一老一少走到伤心崖,后退了几步,突...
一个程序在计算机中是如何运行的?超级干货!!!
强烈声明:本文很干,请自备茶水!???? 开门见山,咱不说废话! 你有没有想过,你写的程序,是如何在计算机中运行的吗?比如我们搞Java的,肯定写过这段代码 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } ...
立即提问