题目大意
:在一条船上,有30个人分成2队,站成一圈,从1开始报数,数到9的那个人就跳河,下一个接着重新从1开始报数,依次类推,求最后活下来是全是一队人的站位编号。
解题思路
:定义1个boolean数据,用来标记30个占位是否还有人,定义一个list用来记录跳河人的编号
题目难点:
怎么循环?循环中怎么记录该跳下去的人员的编号。
代码如下:
public void fun1() {
boolean[] persons = new boolean[30]; //标记位置是否还有人
ArrayList arr = new ArrayList();//记录跳下去人员的编号(索引)
int count = 0; //报数
while (arr.size() < 15) { //结束条件:小与15个人
for (int i = 0; i < persons.length; i++) {
if (persons[i] == false) { //如果该位置有人,有效报数+1
count += 1;
}
if (count == 9) {//报数9,则该人员跳下去
arr.add(i + 1);
persons[i] = true; //标记该位置已经有人了
count = 0; //报数归零
}
}
}
Object[] array = arr.toArray();
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
程序运行结果:
跳河:[5, 6, 7, 8, 9, 12, 16, 18, 19, 22, 23, 24, 26, 27, 30]
未跳:[1, 2, 3, 4, 10, 11, 13, 14, 15, 17, 20, 21, 25, 28, 29]
上面的思路,其实很麻烦,后来讨论别人的想法之后,下面代码我觉得更加巧妙
public void fun2() {
java.util.List person = new ArrayList();
for (int i = 1; i <= 30; i++) {
person.add(i);
}
int count = 0;
while (person.size() != 15) {
Iterator it = person.iterator();
while (it.hasNext()) {
count++;
it.next();
if (count == 9) {
it.remove(); //移除跳河的人
count = 0;
}
}
}
System.out.println(Arrays.toString(person.toArray()));
}
有如下代码,person有a,b两个默认的值,我们使用swap方法交换之后,再置空swap中的person。 请问执行的结果是:?
public class OO {
public static void main(String[] args) {
OO oo = new OO();
Person person = new OO.Person();
oo.swap(person);
System.out.println(person.a + "," + person.b);
}
public void swap(Person person) {
int temp = person.a;
person.a = person.b;
person.b = temp;
person = null;
}
static class Person {
int a = 1;
int b = 30;
}
}
正确答案是:30,1,我以为会抛出空指针异常呢
书上是这样解释的:
java的方法传参只有一种,就是传值,引用类型就就是传递引用地址
以上程序在内存中的分布大概如下:
所以,在swap中置空person变量的对堆内存的引用之后,并没有影响到main方法区中的person变量。
懒汉:
以时间换空间的做法【只有在使用的时候才实例化对象】、线程不安全的
public class Singleton {
//4:定义一个变量来存储创建好的类实例
//5:因为这个变量要在静态方法中使用,所以需要加上static修饰
private static Singleton instance = null;
//1:私有化构造方法,好在内部控制创建实例的数目
private Singleton(){
}
//2:定义一个方法来为客户端提供类实例
//3:这个方法需要定义成类方法,也就是要加static
public static Singleton getInstance(){
//6:判断存储实例的变量是否有值
if(instance == null){
//6.1:如果没有,就创建一个类实例,并把值赋值给存储类实例的变量
instance = new Singleton();
}
//6.2:如果有值,那就直接使用
return instance;
}
}
恶汉式:
以空间换时间的做法【类加载的时候就实例化了对象】、线程是安全的
public class Singleton {
//4:定义一个静态变量来存储创建好的类实例
//直接在这里创建类实例,只会创建一次
private static Singleton instance = new Singleton();
//1:私有化构造方法,好在内部控制创建实例的数目
private Singleton(){
}
//2:定义一个方法来为客户端提供类实例
//3:这个方法需要定义成类方法,也就是要加static
public static Singleton getInstance(){
//5:直接使用已经创建好的实例
return instance;
}
}
我习惯使用的一种单列写法:
Lazy initialization holder class模式,这个模式综合使用了java的类级内部类和多线程缺省同步锁的知识,很巧妙的同时实现了延迟加载和线程安全
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{ //内部类只有在有调用的时候,该内部类才会初始化,达到了延迟加载
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
今天面试被问道饿汉和懒汉,懒汉的线程安全问题,自己嘴贱,说喜欢用Lazy initialization holder class模式来实现加载,大概说了下实现方式,本来是说对了的,对方问了一句话:
使用静态内部类的话类一加载就初始化了,那我直接在类中声明静态变量(懒汉式)有啥区别? 我当时一听,顿时就懵了。回到家,看了下以前的笔记才从圈里走出来:下面是测试
public class Demo {
private static class DemoHoder {
static {
System.out.println("1:内部类被初始化了");
}
private static Demo instance = new Demo();
}
private Demo() {
System.out.println("2:本类初始化了");
}
Demo(String str) {
System.out.println("3:有参数的构造初始化了");
}
public static Demo getInstance() {
return DemoHoder.instance;
}
}
直接使用 Demo.getInstance(); 打印的是
1:内部类被初始化了
2:本类初始化了
直接new Demo(“sss”);打印的是
3:有参数的构造初始化了
从这里可以看出,如果你在Demo中声明一个静态变量Demo demo = new Demo; 那么再执行new Demo(“sss”),那么这个静态变量也会随着一起被实例化,而使用静态内部类来实现单例的话,只有静态内部类被调用的时候才会实例化,也就是说:
类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
而且只有被调用到才会装载,从而实现了延迟加载
题目:String tem = “3456231”; 只许使用jdk的api把这个按升序排列
String tem = "3456231";
char[] arr = tem.toCharArray();
Arrays.sort(arr);
tem = new String(arr);
System.out.println(tem);
实现Runnable接口,或者继承Thread类
new Thread().start();
new Thread(new Runnable() {
public void run() {
}
}).start();