Home • ChemFormatter • iText.NET • JFreeChart.NET • ConcatPDF • iTextFront • TIFF2PPT • J by J# • Programming J#
MSN Search

Home > Windows Programming Tips > Visual J# > Bugs

Windows Programming Tips

 

Visual J#
VJ#のバグ
2nd Ed.で解決済み
これも困る
VJ#2003のバグ

SourceForge.net Logo

Microsoft MVP for Visual Developer - J#

 

Programming Visual J#

English

Visual J# のバグ/Javaに対する非互換性とその回避法

Visual J#コンパイラのバグ

  • 拡張クラスからその基底クラスの内部クラスを参照できない。下記の例では、Application クラスの"Derived.Inner I2 = D1.GetInner();"の行で、Derived.Inner という表現がエラーになる。
    public class Parent {
        public static class Inner {
            Inner() {
            }
        }
        public Inner GetInner() {
            return new Inner();
        }
    }
    public class Derived extends Parent {
        public void DoSomething() {
            /* OK Inner class of parent is visible here */
            Inner I1 = GetInner();
        }
    }
    public class Application {
        public void DoSomething() {
            Parent P1 = new Parent();
            /* OK, Inner class visible through parent */
            Parent.Inner I1 = P1.GetInner();
            Derived D1 = new Derived();
            /* NOT OK, error VJS1161: Cannot find class 'Derived.Inner' error here */
            Derived.Inner I2 = D1.GetInner();
        }
    }
  • イニシャライズ部にバグがあるコードのエラーを検出しない。次のコードは、コンパイルに失敗すべき。(FDBK49016
    Workaround --- プログラムのバグを修正する。
    public class Program {
        public static final int A = 10;
        public static final int B;
        public static final int A_PLUS_B = A + B;

        static {
            B = 100;
        }

        public static void main(String[] args) {
            System.out.println(A);
            System.out.println(B);
            System.out.println(A_PLUS_B);
        }
    }
  • あるクラスが別のパッケージ を拡張し、その基本クラスと拡張クラスに戻り値のシグナチャのみが異なるパッケージローカルのメンバがある場合に、コンパイルに失敗する。FDBK48950
    Workaround --- どちらかのメソッドの名前を変更する。
    package package1;
    public class Program extends package2.BaseClass {
        public static void main(String[] args) {
            System.out.println(new Program().method());
        }
        int method() {
            return 0;
        }
    }
     

    package package2;
    public class BaseClass {
        boolean method() {
            return false;
        }
    }

  • パッケージローカルクラス(AbstractClass)を拡張(ExtendedClass)した場合、AbstractClassから継承したメソッドを呼び出すコードがVJS1161: Cannot find type 'ujihara.ExtendedClass' エラーになる。(FDBK41396
    Workaround --- AbstractClassをパブリッククラスとする。
    public class Program {
        public static void main(String[] args) {
            new ujihara.ExtendedClass().method();
        }
    }
     

    package ujihara;
    public class ExtendedClass extends AbstractClass {
    }


    package ujihara;
    abstract class AbstractClass {
        public void method() {
            System.out.println("method called.");
        }
    }

  • 内部クラスが外部クラスを継承している場合に、間違ったILを生成する場合がある。たとえば、次のプログラムは、2 3 を出力すべきであるが、実際には、1 3を出力する。(FDBK41674
    public class Program {
        int field = 0;
        public Program.Inner createInner() {
            return new Inner();
        }
        public static void main(String[] args) throws Exception {
            Program p = new Program();
            p.field = 1;
            Program.Inner i = p.createInner();
            i.field = 2;
            i.setField(3);
            System.out.println(p.field);
            System.out.println(i.field);
        }

        public class Inner extends Program {
            void setField(int v) {
                Program.this.field = v;
            }
        }
    }
  • カスタムモディファイアを持った型(C++/CLRのlongなど WinFx2.0で導入)を参照すると、間違ったILを出力する。(FDBK40805
    a.cpp:
    #using <mscorlib.dll>
    #include <stdio.h>
    using namespace System;

    namespace AA {
        public ref class A {
        public:
            unsigned long Print() {
                printf("Hello\n");
                return 0;
            }
        };
    }
    b.jsl:
    import AA.*;
    public class Test {
        public static void main(String[] args) {
            A a = new A();
            a.Print();
        }
    }
  • 次のようなコードでは、太字の m は B.m と解釈されるべきだが、A.m と解釈し、それがアクセスできないというエラーが発生する。 (FDBK38703
    Workaround --- mがどのクラスに属しているのかを明示的に指定する。
    public class A {
        private String m = "A.m";
    }

    public class B {
        private String m = "B.m"; // public int m; でも同じ結果

        public class C extends A {
            public String method() {
                return m; // mが参照できないというエラーが発生。
            }
        }
    }
  • 次のように、同じ名前の内部インターフェースを同時にインプリメントしているコードをコンパイルすると InterfaceName が2回実装されているというエラーが発生する。 (FDBK38702
    Workaround --- どちらかのインターフェースの名前を変更する。
    public class Class1 {
        public interface InterfaceName {
        }
    }

    public class Class2 {
        public interface InterfaceName {
        }
    }

    public class Program implements Class1.InterfaceName, Class2.InterfaceName {
        public static void main(String[] args) {
        }
    }
  • interface を extends しても、派生クラスで、再定義する必要がある場合がある。(実証コード探索中)
  • staticフィールドの初期化がされないことがある。(実証コード探索中)
  • 巨大なプロジェクト(特に、エラーが含まれている場合)は、コンパイル中に落ちる。

Visual J# 標準ライブラリのバグ

シリアル化
  • java.io.Serializable ンターフェースを実装していないクラスのClassオブジェクト(クラスのオブジェクトではない) は、シリアル化できるが、逆シリア ル化できない。(FDBK168674
    import java.io.*;
    public class Program {
         public static void main(String[] args) throws Exception {
              ByteArrayOutputStream buffer = new ByteArrayOutputStream();
              ObjectOutputStream out = new ObjectOutputStream(buffer);
              out.writeObject(Class1.class);
              out.writeObject(Program.class);
              out.close();
              ByteArrayInputStream bias = new ByteArrayInputStream(buffer.toByteArray());
              ObjectInputStream in = new ObjectInputStream(bias);
              in.readObject(); // Class1.class can deserialize.
              in.readObject(); // But, Program.class is not. NullReferenceException is thrown here.
              in.close();
         }
    }
    class Class1 implements Serializable {
    }
  • 他にも、うまく動作しない場合多数。
java.lang.String
  • 実体は System.String のシノニムである。
  • Comparableにキャストすると、com.ms.vjsharp.lang.Wrapper.ComparableWrapperForStringというラッパークラスとなる。 これに関連して、次のバグが発生。
    • ((Object)"abc").equals((Comparable)"abc") returns false. (FDBK41211)
  • getBytesがない。
  • .NETでStringにないメソッドは、実際にはヘルパークラスの静的メソッドの呼び出しになる。 これらのメソッドに関連するバグ
    • String.CASE_INSENSITIVE_ORDER.compare("abc", "ABC") により System.FieldAccessException が発生する。 (FDBK41209)
java.math
  • java.math.BigInterger#shiftLeft(int) のバイトを超える繰り上がりが、負の場合、正常に動作しない。たとえば、new BigInteger("-1").shiftLeft(8) は例外を発生し、new BigInteger("-2").shiftLeft(7) は、0 を返す(正しくは、-256)。
java.net
  • ソケット関係のクラスは、非常に不安定。
java.net.URL
  • new URL(String url) のurlとして、file:filename.txt のようなフォーマットをうまく処理しない。
  • new URL(URL context, String spec) の spec 中に .. が含まれている場合に、toString() の値が正規化されていない。具体的には、new URL(new URL("http://test.com/a/b.c"), "../d.e") が、http://test.com/d.e ではなく http://test.com/a/../d.e となる。(FDBK169492
  • URL のデフォルトポート番号を正常に扱わない。たとえば、new URL("http://test.com:80/").equals(new URL("http://test.com/")) は、true を返すべきだが、VJ#では false となる。(FDBK170511
javax.swing.JTree
  • setModel(TreeModel newModel) で newModel を null とすると IllegalArgumentException が発生する。(FDBK38683
java.text.DateFormat
  • DateFormat.getDateInstance(int) で作成される DateFormat オブジェクトのハッシュコードが作成するごとに異なる。次のコードは、true true を表示すべきだが、VJ#では、true false を表示する。(FDBK187845
    import java.text.*;
    public class Program {
        public static void main(String[] args) {
            DateFormat df1 = DateFormat.getDateInstance(DateFormat.SHORT);
            DateFormat df2 = DateFormat.getDateInstance(DateFormat.SHORT);
            System.out.println(df1.equals(df2));
            System.out.println(df1.hashCode() == df2.hashCode());
        }
    }
java.text.StringCharacterIterator
  • new java.text.StringCharacterIterator("ABC", 0, 3, 0).setIndex(3) throws IllegalArgumentException.(FDBK168924
java.util.ArrayList
  • ArrayList の実装がSUNの参照インプリメンテーションと異なる。(FDBK16141
    Workaround --- ArrayListを拡張したい場合は、必要に応じて jp.ujihara.jsharp.util.ArrayList のようなクラスを 継承するようにする。
java.util.GregorianCalendar
  • 次のコードで、Java は、(eD, eM) = (28, 1) を返すが、J#では、(3, 2) を返す。(FDBK98510
    GregorianCalendar gcal = new GregorianCalendar(2006, 0, 31);
    gcal.add(GregorianCalendar.MONTH, 1);
    int eD = gcal.get(GregorianCalendar.DAY_OF_MONTH);
    int eM = gcal.get(GregorianCalendar.MONTH);
java.util.TreeMap

 

Home/CodeTips 294B447F17674A34A3D2B222079C1A22

Copyright (C) 2001-2007 Kazuya Ujihara. All rights reserved.