会员可以在此提问,百战程序员老师有问必答
对大家有帮助的问答会被标记为“推荐”
看完课程过来浏览一下别人提的问题,会帮你学得更全面
截止目前,同学们一共提了 132847个问题
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1263楼
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1264楼
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1265楼
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1266楼
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1267楼
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1268楼

image.png

JAVA 全系列/第一阶段:JAVA 快速入门/JAVA入门和背景知识 1269楼
JAVA 全系列/第一阶段:JAVA 快速入门/JAVA入门和背景知识 1270楼

老师,我测试static关键字时,使用了下面的代码,再TestStatic类中创建构造方法时必须和类名相同,比如我是用User方法名会报错,但在main方法中写了这行代码,是不是意味着系统自动建立了一个没有参数的User构造方法,这样构造方法名与类名不同,为什么没有报错。

User u1 = new User();//????
/**
 * 测试static关键字
 */
public class TestStatic {

    int id;
    String name;
    String pwd;
    static String company = "北京尚学堂";
    /*public void user (int id,String name){ //非构造方法必须有返回值类型(即使是void),
    实例方法方法名也可以与类名相同,但是习惯上我们为实例方法命名的时候通常是小写的,//
        this.id =id;

    }*/

    public TestStatic (int id,String name){  //构造方法与类名相同,其实构造方法的返回类型是void,只不过不能写出来而已
        this.id =id;
        this.name = name;
    }
    public void login(){
        System.out.println("登录名:"+name);
    }
    public static void printCompany(){
        //login();调用非静态成员,编译器就会报错
        // Non-static method 'login()' cannot be referenced from a static context
        System.out.println(company);
    }

    public static void main(String[] args) {
       TestStatic u = new TestStatic(101,"wwq");
       User u1 = new User();//????
       TestStatic.printCompany();
       TestStatic.company = "北京阿里爷爷";
       TestStatic.printCompany();
    }

}


JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1271楼
JAVA 全系列/第一阶段:JAVA 快速入门/控制语句、方法、递归算法 1273楼

本节课最后的那个bug,有一些炮弹会被困在最左侧弹不起来,试着打印了一下坐标,可以看到出bug的阶段坐标变化如图↓

image.png

从打印的坐标可以看出,出现bug时前,x坐标由11减至1,而反向后由1加至10,而判定x坐标越界的标准为x<10,导致反向后x坐标并未跳出越界区间,导致了死循环;据此初步尝试将判断条件x<10调整为想<=10,但实际上这并不能起到作用,以为更改条件后,仍可能出现“x坐标由10减至0,而反向后由0加至9”的情况,实际跑程序也验证了这一点。

所以要从根本上考虑为何会出现“x坐标由11减至1,而反向后由1加至10”的情况,出现两者相差1的情况,让人联想到可能是double转int的过程中出了问题!所以仔细检查了一下x/y坐标迭代的表达式↓

x += speed*Math.cos(degree);
y += speed*Math.sin(degree);

经过检查,表达式中cos(degree)为double型,假设此时cos(degree)=-0.98,speed=10,x=11,则此时会首先计算cos(degree)*speed=-9.8,再计算x+cos(degree)*speed=1.2,对整体强制转换int,得1;而换向后,此时cos(degree)=0.98,speed=10,x=1,此时会首先计算cos(degree)*speed=9.8,再计算x+cos(degree)*speed=10.8,对整体强制转换int,得10,从而出现本节课末尾的bug。y方向同理。

这个结论也揭示了为什么除bug的导弹都是被困在左侧和上侧,因为(int)强制转换为保留整数部分,对于正数来说实际就相当于向下取整,左侧和上侧的碰撞判断条件为x或y小于某值,因此向下取整可能导致连续两次处于碰撞的条件内,从而引发错乱;而对于右侧和下侧,向下取整及时导致碰撞前后坐标不对称,但由于其判断条件为x或y大于某值,向下取整仍可以保证碰撞后下一个坐标不在碰撞的范围内,所以不会出现导弹被困在右侧或者下侧的情况。


所以解决这个bug的关键就在于解决cos(degree)/sin(degree)为正数或负数时,取整的方向不同的问题,比如可以先做判断,碰撞前一次计算使用floor取整,碰撞后一次使用cell取整,或者将迭代公式改写成以下形式↓

x = x + (int)(speed*Math.cos(degree));
y = y + (int)(speed*Math.sin(degree));

对cos(degree)*speed作为一个整体取整,此时结果不论正负,都会对这个double类型的结果仅保留整数部分,因此可以避免碰撞前后坐标不对称的情况,解决bug,实测代码运行,不会出现导弹被困在最左侧或最上边的情况,可以一直跑。

JAVA 全系列/第一阶段:JAVA 快速入门/飞机大战小项目训练 1274楼
JAVA 全系列/第一阶段:JAVA 快速入门/面向对象详解和JVM底层内存分析 1275楼

课程分类

百战程序员微信公众号

百战程序员微信小程序

©2014-2025百战汇智(北京)科技有限公司 All Rights Reserved 北京亦庄经济开发区科创十四街 赛蒂国际工业园
网站维护:百战汇智(北京)科技有限公司
京公网安备 11011402011233号    京ICP备18060230号-3    营业执照    经营许可证:京B2-20212637