1

さて、私はこのnull Pointer例外を受け取りましたが、私も講師もそれを理解できません。(彼はその悪い論理を考慮し、私は同意する傾向があります)

私は自分の3Dオブジェクトを作成し、それを直接ワールドでレンダリングして、xとyの座標をスクリーンペースで調整しています。これにより、演習に必要なものが正確に得られ、コースコンピュータに多くのフレームをドロップすることなく(つまり、講師のnullポインタを再現できない)、スムーズなレンダリングを実現するために数値を調整できますが、実行するとすぐに自宅のビーストマシンはコードフレームがはるかに高速になっているように見え、コンソールにnullポインター例外を吐き出している間(数値を操作してすべてを遅くした場合でも)、レンダリングしているキューブが繰り返し点滅します。ただし、クラッシュすることはありません。

使用されているクラスは次のとおりです。

Viewport.java(JFrameにアタッチ)

package com.my3d.graphics;

import java.awt.BasicStroke;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.util.ArrayList;

import com.my3d.geometry.Cube;
import com.my3d.utils.Props;

public class Viewport extends Canvas implements Runnable
{
    private static final long serialVersionUID = 1L;
    private static final String DEFAULT_NAME = "Viewport";
    private static int viewportCount = 0;

    private static final BasicStroke stroke = new BasicStroke(0.5f);

    private Cube cube;

    private boolean running;

    private String name;
    private int number;

    public Viewport()
    {   
        super();
        //name the Viewport
        if(viewportCount < 10)
            setThisName(DEFAULT_NAME +"_0" +viewportCount);
        else
            setThisName(DEFAULT_NAME +"_" +viewportCount);

        //set Identity
        setNumber(viewportCount);

        //increment the Viewport counter
        viewportCount++;
        cube = new Cube();
        cube.printCubeVertices();
        cube.rotateZ(20);
        cube.printCubeVertices();
        cube.rotateX(20);
        cube.printCubeVertices();
        running = true;
    }

    public Viewport(String n)
    {   
        setThisName(n);

        viewportCount++;
        cube = new Cube();
        //cube.printCubeVertices();
        //cube.rotateZ(20);
    //  cube.printCubeVertices();
        //cube.rotateX(20);
        //cube.printCubeVertices();
        running = true;
    }
    public void tick()
    {
        //cube.rotateY(0.0001);
        //cube.rotateX(0.0001);
        repaint();
        tock();
    }

    private void tock() 
    {
        tick();

    }

    public void setThisName(String n) 
    {
        name = n;
    }

    private void setNumber(int n)
    {
        number = n;
    }

    public Cube getCube()
    {
        return cube;
    }

    public void paint(Graphics g)
    {
         Graphics2D g2 = (Graphics2D)g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setStroke(stroke);
            Vertex[] verts = cube.getVerts();
            for(int i = 0; i < verts.length; i++)
            {
                ArrayList<Vertex> links = verts[i].getLinks();
                for(int j = 0; j < links.size(); j++)
                {
                    Line2D l = new Line2D.Double(verts[i].getPosition().x()+500,/**/verts[i].getPosition().y()+400,/*|*/links.get(j).getPosition().x()+500,/**/links.get(j).getPosition().y()+400);
                    g2.setColor(Color.RED);
                    g2.draw(l);
                }
            }
    }

    @Override
    public void run() 
    {
        int frame = 0;
        while(running)
        {   
            if(frame == 1)
            {
                cube.rotateY(0.0004);
                cube.rotateZ(-0.0005);
                cube.rotateX(-0.0003);
            }
            if(frame > 200000)
            {
                //cube.rotateY(0.0001);
                //cube.rotateZ(0.000015);
                repaint();
                frame = 0;
            }
            frame++;
        }

    }

}

Cube.java

    package com.my3d.geometry;

import java.util.ArrayList;

import com.my3d.graphics.Vector3;
import com.my3d.graphics.Vertex;

public class Cube 
{
    private static final String DEFAULT_NAME = "Cube";
    private static final double DEFAULT_SIZE = 100;
    private static int cubeCount = 0;


    private Vertex[] corners;
    private Vector3 position;
    private Vector3 rotation;
    private String name;
    private int number;


    public Cube()
    {
        if(cubeCount < 10)
            setName(DEFAULT_NAME +"_0" +cubeCount);
        else
            setName(DEFAULT_NAME +"_" +cubeCount);
        //assign Id
        number = cubeCount;
        //Increment cube counter
        cubeCount++;
        corners = new Vertex[8];
        for(int i = 0; i < 8; i++)
            corners[i] = new Vertex();

        corners[0].setPosition(new Vector3(DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE));
        corners[1].setPosition(new Vector3(-DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE));
        corners[2].setPosition(new Vector3(-DEFAULT_SIZE,DEFAULT_SIZE,-DEFAULT_SIZE));
        corners[3].setPosition(new Vector3(DEFAULT_SIZE,DEFAULT_SIZE,-DEFAULT_SIZE));

        corners[4].setPosition(new Vector3(DEFAULT_SIZE,-DEFAULT_SIZE,DEFAULT_SIZE));
        corners[5].setPosition(new Vector3(-DEFAULT_SIZE,-DEFAULT_SIZE,DEFAULT_SIZE));
        corners[6].setPosition(new Vector3(-DEFAULT_SIZE,-DEFAULT_SIZE,-DEFAULT_SIZE));
        corners[7].setPosition(new Vector3(DEFAULT_SIZE,-DEFAULT_SIZE,-DEFAULT_SIZE));

        corners[0].addLink(corners[1]);
        corners[1].addLink(corners[2]);
        corners[2].addLink(corners[3]);
        corners[3].addLink(corners[0]);

        corners[0].addLink(corners[4]);
        corners[1].addLink(corners[5]);
        corners[2].addLink(corners[6]);
        corners[3].addLink(corners[7]);

        corners[4].addLink(corners[5]);
        corners[5].addLink(corners[6]);
        corners[6].addLink(corners[7]);
        corners[7].addLink(corners[4]);

//      corners[0].addLink(corners[5]);
//      corners[1].addLink(corners[6]);
//      corners[2].addLink(corners[7]);
//      corners[3].addLink(corners[4]);
//      
//      corners[0].addLink(corners[2]);
//      corners[5].addLink(corners[7]);



        setPosition(new Vector3());
    }

    public Cube(String n)
    {
        setName(n);
        //assign Id
        number = cubeCount;
        //Increment cube counter
        cubeCount++;
    }
    ////////////////////////////////////////////////////////////////
    //Setters
    ////////////////////////////////////////////////////////////////

    private void setName(String n) 
    {
        name = n;
    }

    private void setPosition(Vector3 v) 
    {
        position = v;
    }

    public Vertex[] getVerts()
    {
        return corners;
    }

    public void printCubeVertices()
    {
        for(int i = 0; i < 8; i++)
            System.out.println(corners[i].getPosition().toString());
    }

    public void rotateZ(double degrees)
    {

        for(int i = 0; i < corners.length; i++)
        {
            double tempZ = corners[i].getPosition().z();
            double newX = (corners[i].getPosition().x()-position.x())*Math.cos(degrees)-(corners[i].getPosition().y()-position.y())*Math.sin(degrees);
            double newY = (corners[i].getPosition().x()-position.x())*Math.sin(degrees)+(corners[i].getPosition().y()-position.y())*Math.cos(degrees);
            corners[i].setPosition(new Vector3(newX,newY,tempZ));

        }
    }

    public void rotateX(double degrees)
    {

        for(int i = 0; i < corners.length; i++)
        {
            double tempX = corners[i].getPosition().x();
            double newZ = (corners[i].getPosition().z()-position.z())*Math.cos(degrees)-(corners[i].getPosition().y()-position.y())*Math.sin(degrees);
            double newY = (corners[i].getPosition().z()-position.z())*Math.sin(degrees)+(corners[i].getPosition().y()-position.y())*Math.cos(degrees);
            corners[i].setPosition(new Vector3(tempX,newY,newZ));
        }
    }

    public void rotateY(double degrees)
    {

        for(int i = 0; i < corners.length; i++)
        {
            double tempY = corners[i].getPosition().y();
            double newZ = (corners[i].getPosition().z()-position.z())*Math.cos(degrees)-(corners[i].getPosition().x()-position.x())*Math.sin(degrees);
            double newX = (corners[i].getPosition().z()-position.z())*Math.sin(degrees)+(corners[i].getPosition().x()-position.x())*Math.cos(degrees);
            corners[i].setPosition(new Vector3(newX,tempY,newZ));
        }
    }
}

Vertex.java

 package com.my3d.graphics;

import java.util.ArrayList;

public class Vertex 
{
    private Vector3 position;
    private ArrayList<Vertex> linked = new ArrayList<Vertex>();

    public Vertex()
    {
        setPosition(new Vector3(0.0,0.0,0.0));
    }

    public Vertex(Vector3 v)
    {
        setPosition(v);
    }

    public void setPosition(Vector3 pos) 
    {
        position = pos;
    }

    public void addLink(Vertex v)
    {
        linked.add(v);
    }

    public void removeLink(Vertex v)
    {
        linked.remove(v);
    }

    /////////////////////////////////////////////////////////////////
    //Getters
    /////////////////////////////////////////////////////////////////

    public Vector3 getPosition()
    {
        return position;
    }

    public ArrayList<Vertex> getLinks()
    {
        return linked;
    }

}

Vector3.java

  package com.my3d.graphics;

public class Vector3 
{

    private double[] xyz;
//  public double x;
//  public double y;
//  public double z;

    public Vector3()
    {
        xyz = new double []{0.0,0.0,0.0};
//      x = xyz[0];
//      y = xyz[1];
//      z = xyz[2];
    }

    public Vector3(double x,double y,double z)
    {
        xyz = new double []{x,y,z};
//      xyz[0] = x;
//      xyz[1] = y;
//      xyz[2] = z;
    }

    public Vector3(double[] array)
    {
        try
        {
            if(array.length > 3)
            {
                RuntimeException e =  new RuntimeException("The Vector3 is too big by (" +(array.length - 3) +") elements you muppet.\nremember that a Vector3 supports arrays with a length of 3. You have (" +array.length +")");
                throw e;
            }
            if(array.length < 3)
            {
                RuntimeException e =  new RuntimeException("The Vector3 is too small by (" +(3 - array.length) +") elements you muppet.\nremember that a Vector3 supports arrays with a length of 3. You have (" +array.length +")");
                throw e;
            }
            xyz[0] = array[0];
            xyz[1] = array[1];
            xyz[2] = array[2];
        }
        catch(RuntimeException e)
        {
            System.out.println(e);
        }
    }

///////////////////////////////////////////////////////////////////////////

    public void x(double a)
    {
        xyz[0] = a;
    }

    public void y(double a)
    {
        xyz[1] = a;
    }

    public void z(double a)
    {
        xyz[2] = a;
    }

    public double x()
    {
        return xyz[0];
    }

    public double y()
    {
        return xyz[1];
    }

    public double z()
    {
        return xyz[2];
    }

    public void normalize()
    {
        double length = Math.sqrt((xyz[0] * xyz[0]) + (xyz[1] * xyz[1]) + (xyz[2] * xyz[2]));
        xyz[0] = xyz[0]/length;
        xyz[1] = xyz[1]/length;
        xyz[2] = xyz[2]/length;
    }

    public String toString()
    {
        return "(" + xyz[0] + "," + xyz[1] + "," + xyz[2] + ")"; 
    }
}

私ができる最善のことはpublic double x(){return xyz[0];} 、ビューポートクラスでpaintメソッドが呼び出されたときにVector3クラスでそれをトレースすることですが、ステップスルーしようとすると、それらがnullになることはありません。回転中に頂点に新しい位置を再割り当てしようとしているときに、jvmがそれ自体に追いついているような印象を受けます。

編集:スタックトレース

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.my3d.graphics.Vector3.x(Vector3.java:70)
at com.my3d.graphics.Viewport.paint(Viewport.java:107)
at java.awt.Canvas.update(Unknown Source)
at sun.awt.RepaintArea.updateComponent(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

追加情報:

Manager.java

    package com.my3d.core;

import java.awt.Color;

import com.my3d.graphics.Viewport;
import com.my3d.graphics.Wind;
import com.my3d.utils.Props;

public class Manager {

    /**
 * @param args
 */
public static void main(String[] args) 
{
    Props.loadPropsFromFile();
    Wind wind = new Wind();
    wind.setVisible(true);
    Viewport view = new Viewport("Main view");
    view.setPreferredSize(Props.getWindowSize());
    view.setBackground(Color.LIGHT_GRAY);
    wind.add(view);
    view.setVisible(true);
    wind.pack();
    view.run();
}

}

Wind.java

    package com.my3d.graphics;

import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;

import com.my3d.utils.Props;

import javax.swing.JFrame;

public class Wind extends JFrame
{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private boolean fullScreen = false;
    //Constructor
    public Wind()
    {
        super(Props.getDefaultTitle() +Props.getTitleSplash());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fullScreen = Props.getFullScreen();
        if (fullScreen)
        {
            setUndecorated(true);
            GraphicsDevice vc;
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            vc= ge.getDefaultScreenDevice();
            vc.setFullScreenWindow(this);
        }
        else
        {
            setBounds(0,0,Props.getWindowWidth(),Props.getWindowHeight());
            setLocationRelativeTo(null);
        }
    }

    public void setTitle(String s)
    {
        //if(Props.getRandomSplashes())
        super.setTitle(Props.getDefaultTitle() +s);
    }

    public void setRandomTitle()
    {
        if(Props.getRandomSplashes())
            Props.setTitleSplash(Props.randomizeSplash());
            super.setTitle(Props.getDefaultTitle() +Props.getTitleSplash());
    }

    public void setFullScreen(boolean b)
    {
        fullScreen = b;
    }








    //this method wont work >>
    public void refactorWindow()
    {
        if (fullScreen)
        {
            setUndecorated(true);
            GraphicsDevice vc;
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            vc= ge.getDefaultScreenDevice();
            vc.setFullScreenWindow(this);
        }
        else
        {
            setSize(Props.getWindowSize());
            setLocationRelativeTo(null);
        }
    }

}

Props.java

    package com.my3d.utils;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

import javax.imageio.ImageIO;

public class Props 
{   
    private static String gameTitle;
    private static String splashTitle;

    private static Dimension windowSize;

    //private static int gameState;

    private static boolean fullScreen;
    private static boolean randomSplashes;
    private static BufferedImage tileSheet;


    ///////////////////////////////////////////////////////////////
    //Getters
    ///////////////////////////////////////////////////////////////

    public static Dimension getWindowSize()
    {
        return windowSize;
    }

    public static int getWindowWidth()
    {
        return (int) windowSize.getWidth();
    }

    public static int getWindowHeight()
    {
        return (int) windowSize.getHeight();
    }

    public static String getTitleSplash() 
    {
        return splashTitle;
    }

    public static String getDefaultTitle() 
    {
        return gameTitle;
    }

    public static boolean getFullScreen()
    {
        return fullScreen;
    }

    public static boolean getRandomSplashes()
    {
        return randomSplashes;
    }

    public static BufferedImage getTileSheet()
    {
        return tileSheet;
    }

    /////////////////////////////////////////////////////////////////////
    //Setters
    /////////////////////////////////////////////////////////////////////

    public static void setWindowSize(int width, int height) 
    {   
        windowSize = new Dimension(width,height);   
    }

    public static void setTitleSplash(String s) 
    {
        splashTitle = s;
    }

    private static void setDefaultTitle(String s) 
    {
        gameTitle = s;      
    }

    ////////////////////////////////////////////////////////////////////
    //loader
    ////////////////////////////////////////////////////////////////////

    public static void loadPropsFromFile() 
    {
        File file = new File("res\\config\\props.props");
        try 
        {
            Scanner input = new Scanner(file);
            String lInput = input.nextLine().trim();
            setWindowSize(Integer.parseInt(lInput.substring(lInput.indexOf('=')+1,lInput.indexOf(','))),Integer.parseInt(lInput.substring(lInput.indexOf(',')+1,lInput.length())));
            lInput = input.nextLine().trim();
            if(lInput.substring(lInput.indexOf('=')+1,lInput.length()).equals("true"))
                fullScreen = true;
            else
                fullScreen = false;
            lInput = input.nextLine().trim();
            if(lInput.substring(lInput.indexOf('=')+1,lInput.length()).equals("true"))
            {
                lInput = input.nextLine().trim();
                setDefaultTitle(lInput.substring(lInput.indexOf('=')+1,lInput.length()));
                randomSplashes = true;
                setTitleSplash(randomizeSplash());
            }
            else
            {
                lInput = input.nextLine().trim();
                setDefaultTitle(lInput.substring(lInput.indexOf('=')+1,lInput.length()));
                setTitleSplash("");
                randomSplashes = false;

            }
            lInput = input.nextLine().trim();
            try 
            {
                tileSheet = ImageIO.read(new File(loadFromDirectory(lInput.substring(lInput.indexOf('=')+1,lInput.length()))));
            } 
            catch (IOException e) 
            {
                System.out.println("Tilesheet Cannot be found.");
            }
        } 
        catch (FileNotFoundException e) 
        {
            e.printStackTrace();
        }

    }

    ///////////////////////////////////////////////////////////////////
    //Utility
    ///////////////////////////////////////////////////////////////////

    public static String loadFromDirectory(String key)
    {   
        String s = "";
        File sFile = new File("res\\config\\dirs.dir");
        try 
        {
            Scanner sInput = new Scanner(sFile);
            while(sInput.hasNextLine())
            {   
                String st = sInput.nextLine().trim();
                if(key.equals(st.substring(1,st.length())));
                s = sInput.nextLine().trim();
            }
        } 
        catch (FileNotFoundException e) 
        {
            e.printStackTrace();
        }

        return s;

    }

    public static String randomizeSplash()
    {
        if(randomSplashes)
        {
            File sFile = new File("res\\config\\splash.props");
            ArrayList<String> sArray = new ArrayList<String>();
            try 
            {
                Scanner sInput = new Scanner(sFile);
                while(sInput.hasNextLine())
                {
                    sArray.add(sInput.nextLine().trim());
                }
            } 
            catch (FileNotFoundException e) 
            {
                e.printStackTrace();
            }
            Random rand = new Random();
            String s = sArray.get(rand.nextInt(sArray.size()));
            splashTitle = s;
            return s;
        }
        else
            return "";
    }






}

props.props

windowSize =1000,800
startInFullscreen =false
randomSplashes =false
defaultTitle =3D Prototype
tileSheet =tileSheet

dirs.dir

<startGame>
res\\img\\button\\Start_game_text.png
res\\img\\button\\Start_game_active.png
res\\img\\button\\Start_game_click.png
<quitGame>
res\\img\\button\\Quit_game_text.png
res\\img\\button\\Quit_game_active.png
res\\img\\button\\Quit_game_click.png
<menuBackground>
res\\img\\Menu_background.png
<resumeGame>
res\\img\\button\\Resume_game_text.png
res\\img\\button\\Resume_game_active.png
res\\img\\button\\Resume_game_click.png
<tileSheet>
res\\img\\Final_Sub_Hunt.png
4

2 に答える 2

1
    catch(RuntimeException e)
    {
        System.out.println(e);
    }

このセグメントを使用すると、配列を適切に初期化せずに Vector3 を作成できます。それは潜在的な問題です。

デフォルト以外のコンストラクターはどちらも、割り当て前に x、y、または z が null であることを確認しようとはしません。

そこから始めて、次に単体テストを検討します。

于 2013-03-15T19:22:26.137 に答える
1

更新xyz: フィールドをVector3としてマークしますfinal。JMM を読んだところ、シンクロナイザーまたはファイナルがなければ、イベント ディスパッチ スレッド (EDT) が、スタック トレースが発生する場所から、非ファイナル フィールドがコンストラクターによってまだ初期化されていないことを確認することは合法であることがわかりました。別の(あなたのViewport.run())スレッドで実行されます。この SO の質問またはJMM FAQを参照してください。

JLS でこれを確認する正しい場所は、セクション 17.5です (ただし、これを理解し始めるには、17 のすべてを何度も読む必要があります)。

コンストラクターが終了すると、オブジェクトは完全に初期化されたと見なされます。オブジェクトが完全に初期化された後にのみオブジェクトへの参照を確認できるスレッドは、そのオブジェクトの final フィールドの正しく初期化された値を確認できることが保証されます。

final 以外のフィールドには同じ保証が適用されないことに注意してください。そこで安全が必要な場合は、何らかの同期エッジを使用する必要があります (明示的なシンクロナイザー、揮発性など)。

Alex Miller からの関連する議論.

元の回答

フィールドVector3(double[])を初期化しないコンストラクターにエラーがあるようです。double[] xyzそのフィールドが初期化されず、NPE が発生する場所を見つけることができた唯一の場所。

あなたのコードから、あなたが実行しているスレッドの数を知ることはできません。1 つのスレッドでのインスタンスを作成Vector3し、それらが別のレンダリング スレッドによって表示されている間にそれらをコレクションに配置している場合、部分的な構築の状態でそれらを観察している可能性があります。一般的には、これが起こりそうにないように調整されています (部分的に構築されたオブジェクトの公開についてメモリ モデルが何を言っているのか、頭の中で思い出すことはできませんがthis、コンストラクタから抜け出すと発生する可能性があります。わかりません)。ここで起こっていること。)

于 2013-03-15T19:15:35.833 に答える