こっそり、、勉強中
忘れてググる自分用
定数
final データ型 定数名 = 値
null
参照先がない状態のこと
空("")の文字列は、参照先に空の文字列がある状態なので、nullではない
→プリミティブ型には、nullという状態はない
比較したい
nullでは、equalsメソッドを使うと、例外が発生する。(NullPointerException)
「==」演算子を使う。
空文字は
「isEmpty」メソッドを使うとよい
継承
既存のクラスを拡張して作れる
サブクラスはスーパークラスのフィールド、メソッドを引き継ぐ。
スーパークラスのメソッドにアクセスするには、superキーワードを使う
サブクラスのメソッドにアクセスするには、thisキーワードを使う。
スーパークラスは1つで、サブクラスは複数いる。
super.hoge();
オーバライド
親のメソッド名、戻り値、引数を一致させたものを子クラスに実装する
明示的に「@Override」をつけるといいらしい。
//子クラス
@Override
void hoge(){
}
オーバライドしたメソッドは、サブクラスのものが優先される。
抽象クラス
インスタンスを作れないクラス
abstract class TestClass {
void test() {
System.out.println("TEST");
}
}
public class SampleProgram {
public static void main(String[] args) {
//コンパイルエラー:型 TestClass のインスタンスを生成できません
TestClass tc = new TestClass();
}
}
抽象メソッド
- メソッド内に命令の入ってないメソッドのこと
- 抽象メソッドは、抽象クラスに定義する
- 抽象クラスを継承したサブクラスは、抽象メソッドをオーバーライドしない限り抽象クラスのまま(??)
abstract class TestClass {
//普通のメソッド
void test() {
System.out.println("TEST");
}
//抽象メソッド
abstract void test2();
}
abstract class TestClass {
//コンパイルエラー:抽象メソッドは本文を指定しません
abstract void test() {
System.out.println("TEST");
}
}
抽象クラスを継承しても、サブクラスを抽象クラスに定義すれば、オーバーライドが必要ないってことなのかな。。
abstract class TestClass {
//普通のメソッド
void test() {
System.out.println("TEST");
}
//抽象メソッド
abstract void test2();
}
//コンパイルエラーにならない
abstract class subClass extends TestClass {
}
//コンパイルエラー:型 subClass は継承された抽象メソッド TestClass.test2() を実装する必要があります
class subClass extends TestClass {
}
インターフェース
- クラスが持つべき、メソッドを定義したもの
- インターフェースで定義したものは、クラスで実装する
- クラスで実装するものは、インターフェースで定義したメソッドすべて。
- 継承のように、1対Nではなく。N対Nの多重継承ができる。
- インターフェースで定義されたメソッドは、暗黙的に「public abstract」修飾子付きとして扱われるので、実装する際は、必ず「public」修飾子を付ける。
- クラスでインターフェースを実装するときは、インターフェースを「,」で区切る
- メソッドだけじゃなくて、定数も定義できる
インターフェースのフィールドで定義された変数は、修飾子なしで、暗黙的に
「public static final」付き、つまり、定数になる。 - インターフェースもインターフェースを継承できる。
interface testIf{
int test();
void test2(String msg);
}
interface testIf{
void test2(String msg);
}
//コンパイルエラー:型 test は継承された抽象メソッド testIf.test2(String) を実装する必要があります
class test implements testIf{
}
//コンパイルエラー:testIf から継承されたメソッドの可視性を下げることはできません
class test implements testIf{
void test2(String msg) {
System.out.println(msg);
}
}
// コンパイルエラーなし
class test implements testIf{
public void test2(String msg) {
System.out.println(msg);
}
}
インターフェースを複数継承
interface testIf1{
void test1(String msg);
}
interface testIf2{
int test2();
}
class test implements testIf1, testIf2{
public void test1(String msg) {
System.out.println(msg);
}
public int test2() {
return 1;
}
}
インターフェースで定数定義
interface testIf1{
int HOGE = 1;
public static final String HOGE2 = "定数";
}
class test implements testIf1{
int i = testIf1.HOGE;
//コンパイルエラー:final フィールド testIf1.HOGE には代入できません
//testIf1.HOGE = 1;
void testPrint() {
System.out.println(testIf1.HOGE2);
}
}
public class SampleProgram {
public static void main(String[] args) {
test t = new test();
t.testPrint();
}
}
インターフェースの継承
interface testIf1{
int HOGE = 1;
public static final String HOGE2 = "定数";
void test();
void test2();
}
//インターフェースの継承
interface testIf2 extends testIf1{
void test();
}
//コンパイルエラー:型 test は継承された抽象メソッド testIf1.test2() を実装する必要があります
class test implements testIf2{
@Override
public void test() {
// TODO 自動生成されたメソッド・スタブ
}
}
//コンパイルエラーなし
class test implements testIf2{
@Override
public void test() {
// TODO 自動生成されたメソッド・スタブ
}
@Override
public void test2() {
// TODO 自動生成されたメソッド・スタブ
}
}
親インターフェースと、子インターフェースで同じメソッド定義があっても、エラー扱いにはならないんだなぁ。。混乱のもとにはなりそうだけど。
ポリモーフィズム
日本語では多態性(多様な動作をする)という意味。
- スーパークラスの型の変数に、サブクラスのインスタンスを代入できる
- インターフェースの型の変数に、インターフェースを実装したクラスのインスタンスを代入できる
- メソッドを呼び出すと、変数の型に関係なく、変数が参照するメソッドが実行される。(難しい。。)
import java.util.ArrayList;
import java.util.List;
interface TestIf{
public abstract void run();
}
class TestAAA implements TestIf{
String myClassName = "TestAAA";
@Override
public void run() {
// TODO 自動生成されたメソッド・スタブ
System.out.println(myClassName);
}
}
class TestBBB implements TestIf{
String myClassName = "TestBBB";
@Override
public void run() {
// TODO 自動生成されたメソッド・スタブ
System.out.println(myClassName);
}
}
public class SampleProgram {
public static void main(String[] args) {
//インターフェース型のコレクション、配列を用意
List<TestIf> list = new ArrayList<TestIf>();
TestIf[] array = new TestIf[2];
//コレクションに各インスタンスを設定
list.add(new TestAAA());
list.add(new TestBBB());
//配列に各インスタンスを設定
array[0] = new TestAAA();
array[1] = new TestBBB();
System.out.println("コレクション");
for(TestIf ti: list) {
ti.run();
}
System.out.println("配列");
for(int i = 0; i < array.length; i++) {
array[i].run();
}
}
}
コピー
配列のコピー
array2は、array1の参照になる。
array2の要素を書き換えると、array1にも影響する。
逆も同じ。
int[] array1 = {1,2,3};
int[] array2 = array1;
cloneメソッドを使えば、値のコピーができる。
コレクションも同様。
int[] array2 = array1.clone();
シャローコピー、ディープコピー
cloneメソッドでは不十分な時がある。
要素がプリミティブ型ではなく、オブジェクト型の場合
オブジェクト型は値ではなく、参照先を要素としているので、参照先にある値までコピーはしない。これをシャローコピーという。
これだと、複数のオブジェクトで同じ値を共有することになる。
参照先の値までコピーするのをディープコピー。
どこまでコピーするかはプログラム次第。
大変そう。。
ジャネリクス(Generics)
型を「<」「>」で囲んで、表記することで、型を強制するための指定
ジェネリクスを使ったパターン
String型しか入らない。
List<String> list = new ArrayList<String>();
ジェネリクスを使ってないパターン
Eclipse上で注意メッセージは出るけど使える。
データの型を指定しないので、プリミティブ型以外は何でもはいる。
List list = new ArrayList();
ジェネリクスの利点
- 明示的なキャストがいらない
- キャストは処理を遅くする可能性がある
- どんなデータが入るかわかりやすい
List list = new ArrayList();
List<String> list2 = new ArrayList<String>();
// キャストが複雑
System.out.println(((String) list.get(0)).length());
// 普通のString型と同じように使える
System.out.println(list2.get(0).length());
確かに、ジェネリクスを使ったほうが、楽かも。
Eclipseくんは優秀だけど。
配列
配列の要素数
配列名.length
繰り返し色々
基本
public class SampleProgram {
public static void main(String[] args) {
int[] box = {0,1,2,3,4,5,6,7,8,9};
for(int i = 0; i < 10; i++) {
if(i == 5) {
System.out.println(i+1+":"+box[i]+"_continue");
continue;
}else if(i == 7) {
System.out.println(i+1+":"+box[i]+"_break");
break;
}
System.out.println(i+1+":"+box[i]);
}
}
}
//結果
1:0
2:1
3:2
4:3
5:4
6:5_continue
7:6
8:7_break
public class SampleProgram {
public static void main(String[] args) {
int[] box = {0,1,2,3,4,5,6,7,8,9};
int i = 0;
while(i < 10) {
System.out.println(i+1+":"+box[i]);
i++;
}
}
}
public class SampleProgram {
public static void main(String[] args) {
int[] box = {0,1,2,3,4,5,6,7,8,9};
int i = 0;
do {
System.out.println(i+1+":"+box[i]);
i++;
}while(i < 10);
}
}
do~whileなんて久しぶりに見たな・・
添え字って増えてくると、名前のストックがなくなってくる。。
拡張For文
import java.util.HashSet;
import java.util.Set;
public class SampleProgram {
public static void main(String[] args) {
// 値の重複を許さない
// 順序の保証もない
Set<String> hs = new HashSet<String>();
hs.add("白");
hs.add("赤");
hs.add("白");
hs.add("緑");
int[] array = {1,2,3,1};
// HashSetにはgetメソッドがない
// for(int i = 0; i < hs.size(); i++) {
// System.out.println(hs.(i));
// }
// 拡張for 文
for(String item : hs) {
System.out.println(item);
}
for(int i : array) {
System.out.println(i);
}
}
}
//結果
緑
赤
白
1
2
3
1
ラムダ式
むずかしい・・
いろいろ
public class TestMain {
public static void main(String[] args) {
List<String> cities = new ArrayList<String>();
cities.add("京都");
cities.add("大阪");
cities.add("愛知");
System.out.println("ループ1");
for(int i = 0; i < cities.size(); i++) {
System.out.println(cities.get(i));
}
System.out.println("ループ2");
for(Iterator<String> ite = cities.iterator(); ite.hasNext();) {
System.out.println(ite.next());
}
System.out.println("ループ3:拡張forループ");
for(String city : cities) {
System.out.println(city);
}
System.out.println("ループ4:");
cities.forEach(new Consumer<String>() {
public void accept(final String citiy) {
System.out.println(citiy);
}
});
System.out.println("ループ5:ラムダ式");
cities.forEach((final String city) -> System.out.println(city));
System.out.println("ループ6:ラムダ式");
cities.forEach(System.out::println);
}
}
map
キーと値の一覧の繰り返し
import java.util.HashMap;
import java.util.Map;
public class SampleProgram {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>(){
{
put("001","赤");
put("002","青");
put("003","緑");
}
};
// 値
for(String item : map.values()) {
System.out.println(item);
}
// キー
for(String item : map.keySet()) {
System.out.println(item);
}
}
}
デフォルトエンコーディング
javac でコンパイルするとき
サクラエディタや、メモ帳で何気なく、ソースコードを書き
javac hoge.java
と何気なく、コンパイルしたり
Eclipse上でボタンをぽちっとして実行したりしてるだけだと気づかなかった。
Eclipse上で作成したソースコードを、DOS上で手動でコンパイルしたら
//ソースコード
public class SampleProgram {
public static void main(String[] args) {
System.out.println("ほげ");
}
}
//結果
C:\MyWork\>javac SampleProgram.java
SampleProgram.java:6: エラー: この文字は、エンコーディングMS932にマップできません
System.out.println("縺サ縺?");
^
エラー1個
C:\MyWork\>
これは、ソースファイルが「UTF-8」で、Windowsのデフォルトエンコーディングが「MS932」の不一致で発生する。
javacでコンパイルするときに、エンコーディングを指定しないと、JVM(?)のデフォルトエンコーディングでコンパイルされる。
環境がWindowsで、ファイルのエンコーディングが「UTF-8」なら、
javac -encoding utf8 SampleProgram.java
とすれば無事コンパイル出来る。
デフォルトエンコーディングの確認の仕方
import java.util.Properties;
import java.util.Enumeration;
class sampleEncoding{
public static void main(String args[]){
System.out.println(System.getProperty("file.encoding"));
}
}
デフォルトエンコーディングの変更
デフォルトエンコーディングはJavaプログラムで入出力でも影響があるらしく。
ファイルを読み込んだりするときに、ファイルのエンコードを指定しないと
デフォルトエンコーディングが使われるみたいなので、
デフォルトエンコーディングが「utf8」の環境で、
読み込むファイルが「euc」の場合、エンコーディングを指定しないと
文字化けを起こす。
デフォルトエンコーディングを事前に変更しておけば、ソースコードや入力ファイルを修正
しなくても、一応文字化けしないし、コンパイルも出来る。
REM windowsの場合
set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
C:\MyWork>javac SampleProgram.java
SampleProgram.java:6: エラー: この文字は、エンコーディングMS932にマップできません
System.out.println("縺サ縺?");
^
エラー1個
C:\MyWork>set JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
C:\MyWork>javac SampleProgram.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
C:\MyWork>
金銭計算の時は、floatやdoubleを使わない
内部で2進数に変換されて計算されるときに、誤差が生じるらしい
BigDecimalクラスを使うらしい。
2進数に変換せず計算するらしい。
import java.math.BigDecimal;
public class SampleProgram {
public static void main(String[] args) {
double xx = 1.0;
double yy = 0.9;
System.out.println(xx - yy);
System.out.println(xx / yy);
BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("0.9");
System.out.println(x.subtract(y));
System.out.println(x.divide(y, 2, BigDecimal.ROUND_UP));
System.out.println(x.divide(y, 2, BigDecimal.ROUND_DOWN));
System.out.println(x.divide(y, 2, BigDecimal.ROUND_HALF_UP));
System.out.println(x.divide(y, 3, BigDecimal.ROUND_HALF_DOWN));
System.out.println(x.divide(y, 2, BigDecimal.ROUND_HALF_UP));
System.out.println(x.divide(y, 3, BigDecimal.ROUND_HALF_DOWN));
}
}
//結果
0.09999999999999998
1.1111111111111112
0.1
1.12
1.11
1.11
1.111
1.11
1.111
BigDecimal.ROUND_HALF_UPと、BigDecimal.ROUND_HALF_DOWNは何が違うのだろうか・・
コメントをもらって、改めて調べた結果
BigDecimal.ROUND_HALF_UPは、四捨五入
BigDecimal.ROUND_HALF_DOWNは、五捨六入
でした。
全然違うんですねぇ。。。
import java.math.BigDecimal;
import java.text.DecimalFormat;
public class SampleProgram {
public static void main(String[] args) {
DecimalFormat format = new DecimalFormat("#.#");
BigDecimal x = new BigDecimal("10.55");
BigDecimal xx = x.setScale(1, BigDecimal.ROUND_HALF_UP);
System.out.println("小数第2位で四捨五入 : " + format.format(xx));
BigDecimal xxx = x.setScale(1, BigDecimal.ROUND_HALF_DOWN);
System.out.println("小数第2位で五捨六入 : " + format.format(xxx));
}
}
//結果
小数第2位で四捨五入 : 10.6
小数第2位で五捨六入 : 10.5
ちなみに、divideに割る数だけしか指定しないと、以下の例外が・・・
計算結果が循環小数になるのが原因らしい
System.out.println(x.divide(y));
//例外
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1690)
at SampleProgram.main(SampleProgram.java:15)
数字のソース上の見栄え
「_」で区切りをつけることができる。
表示結果、計算に影響が出ない。うーん。。。定数定義とかなら便利か?
int x = 1_000;
違う型に代入したい
キャストは相互性があるものしか使えない
int x = 12;
int y = 5;
double ans = (double)x / (double)y;
相互関係にあるもの
- プリミティブ型同士
- クラスの継承元が同じ
- 同じインターフェースが実装されている
でも、数値を文字列に変換したい
String.valueOfメソッドを使う
使い方は、
クラス名.メソッド名
int x = 1234;
String ss = String.valueOf(x);
文字列型になったので、lengthメソッドが使える。
public class SampleProgram {
public static void main(String[] args) {
int x;
x = 123 * 234;
System.out.println(String.valueOf(x).length());
}
}
クラスに対して呼び出すメソッドを
- 静的メソッド
- staticメソッド
- クラスメソッド
という、逆にオブジェクトに対して(変数に対して)呼び出すメソッドを
instanceメソッドという。
見分け方は、「static」があるかないか。
文字列を数字にしたい
プリミティブ型をラッパークラスを使って、オブジェクトに変換する。
プリミティブ型 | ラッパークラス |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
import java.io.IOException;
public class SampleProgram {
public static void main(String[] args) throws IOException {
String x = "123";
String xx = "12.45";
int y;
double yy;
// String型へ、プリミティブ型は代入できない
//y = x;
y = Integer.valueOf(x);
System.out.println(y);
yy = Double.valueOf(xx);
System.out.println(yy);
}
}
//結果
123
12.45
まとめ
- プリミティブ型同士は、キャストで対応(ex. (double)i / (double)ii)
- String型→プリミティブ型は、Stringクラスのメソッドで対応
- プリミティブ型→String型は、ラッパークラスで対応
ファイルの入出力
入力1
ただclose()を書くと、「処理されない例外の型 IOException」とエラーになってしまうので、スロー宣言の追加してます。。
(java1.6が現役のプロジェクトってまだまだあるんだな。。って思う2021年)
package prototype.test.readfile;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
System.out.println("Start.......");
// Fileオブジェクトは文字列が書き込まれているファイルを表す
String filePath = "C:\\MyWork\\work\\eclipse-workspace\\file\\input.txt";
File file = new File(filePath);
BufferedReader br =null;
try {
// Fileオブジェクトから文字列を受け取る
FileReader fr = new FileReader(file);
// 受け取った文字列を蓄えておき、要求に応じて文字列を渡す
br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}finally {
System.out.println("close!!");
br.close();
}
System.out.println("End.........");
}
}
//結果
Start.......
Test 1
Test 2
close!!
End.........
入力2
入力1のtyr-catch文をtry-with-resources文に変更。
package prototype.test.readfile;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* try-with-resourcesを使ったバージョン
* java1.7から仕様可能
*
*/
public class Main2 {
public static void main(String[] args) throws IOException {
System.out.println("Start.......");
String filePath = "C:\\MyWork\\work\\eclipse-workspace\\file\\input.txt";
File file = new File(filePath);
try(
//リソースの宣言 ここで宣言した変数に対して、自動的にclose()メソッドが呼ばれる
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
)
{
String line = null;
while((line = br.readLine()) != null) {
System.out.println(line);
}
}catch (Exception e) {
e.printStackTrace();
}
System.out.println("End.........");
}
}
enum
--Const.java
package prototype.test.Const;
public class Const {
public static enum PEN {
pencil("えんぴつ"),
ballpoint_pen("ボールペン"),
fountain_pen("万年筆");
private String name;
/**
* プライベートコンストラクタ 列挙型のインスタンス生成を抑止します
*/
private PEN(String name) {
this.name = name;
}
public String getValue() {
return this.name;
}
}
}
--Main2.java
package prototype.test.Const;
import prototype.test.Const.Const.PEN;
public class Main2 {
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
String pen = "えんぴつ";
System.out.println("pen["+pen+"]");
if(PEN.pencil.getValue().equals(pen)) {
System.out.println("OK");
}else {
System.out.println("NG");
}
}
}
条件の書き方
IF文
いろんな言語をやり始めると、「else if」の書き方がわからなくなる。。
基本形
if(条件1) {
}else if(条件2) {
}else {
}
比較演算子
演算子 | 意味 |
---|---|
== | 等しい |
!= | 異なる |
> | - |
>= | - |
< | - |
<= | - |
論理演算子
- AND:&&
- OR:||
- NOT:!
「==」と「equals」
「==」はオブジェクト(アドレス)が同じであるかを判断するもの、
値が同じであるかは「equals」を使う。
「equals」はプリミティブ型以外の型には備わっている。
(参照型と、基本型の違い。基本型は値が格納されているが、参照型は、オブジェクトのアドレスが格納されているから。。??)
正規表現
難しい。。
public class SampleProgram {
public static void main(String[] args) {
String[] tell = {"090-1234-1234","1234-1234-1234","090-O123-1234"};
/*
* 3桁の数字 - 4桁の数字 - 4桁の数字
*/
for(int i = 0; i < tell.length; i++) {
System.out.println(tell[i]);
if(tell[i].matches("\\d{3}-\\d{4}-\\d{4}")) {
System.out.println("正解");
}else {
System.out.println("不正解");
}
}
}
}
//結果
090-1234-1234
正解
1234-1234-1234
不正解
090-O123-1234
不正解
例外
基本形
finallyはあんまり使わないのかな。。
try{
}catch(例外のクラス 変数名){
}finally{
}
メソッドの外へ投げる
メソッド内で例外が発生した場合に、同メソッド内でキャッチせずに、メソッドの外へ投げることができる。外で例外をキャッチしないといけない。
戻り値 メソッド名(引数) throws 例外の型 {
}
try-with-resources構文というのもあるのか。。。
Java7からの機能らしい。
今は置いておこう。。
コメントで使い方を教えてもらいました!
便利かも。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class SampleProgram {
public static void main(String[] args) {
String fileName1 = "C:\\test3.txt";
String fileName2 = "C:\\test4.txt";
//String fileName1 = null;
try (
FileReader fr = new FileReader(new File(fileName1));
BufferedReader bfr = new BufferedReader(fr);
FileReader fr2 = new FileReader(new File(fileName2));
BufferedReader bfr2 = new BufferedReader(fr2);
)
{
String ss = null;
while((ss = bfr.readLine()) != null) {
System.out.println(ss + "を読み込みました");
//throw new IOException();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
//基本形
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class SampleProgram {
public static void main(String[] args) {
try {
File file = new File("C:\\test3.txt");
FileReader fr = new FileReader(file);
BufferedReader bfr = new BufferedReader(fr);
String ss = null;
while((ss = bfr.readLine()) != null) {
System.out.println(ss + "を読み込みました");
}
bfr.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
//結果
java.io.FileNotFoundException: C:\test3.txt (指定されたファイルが見つかりません。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileReader.<init>(FileReader.java:72)
at SampleProgram.main(SampleProgram.java:12)
//例外を外へ投げる
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class SampleProgram {
public static void main(String[] args) throws IOException {
File file = new File("C:\\test3.txt");
FileReader fr = new FileReader(file);
BufferedReader bfr = new BufferedReader(fr);
String ss = null;
while((ss = bfr.readLine()) != null) {
System.out.println(ss + "を読み込みました");
}
bfr.close();
}
}
//結果
Exception in thread "main" java.io.FileNotFoundException: C:\test3.txt (指定されたファイルが見つかりません。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileReader.<init>(FileReader.java:72)
at SampleProgram.main(SampleProgram.java:11)
自分で例外を作る
既存のクラスを使う
throwで投げられるのは、Throwableを継承したクラスのインスタンス。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class SampleProgram {
public static void main(String[] args) throws IOException {
try {
File file = new File("C:\\test3.txt");
FileReader fr = new FileReader(file);
BufferedReader bfr = new BufferedReader(fr);
String ss = null;
while((ss = bfr.readLine()) != null) {
System.out.println(ss + "を読み込みました");
}
bfr.close();
}catch(IOException e) {
IOException ee = new IOException("IOExceptionが発生!!");
throw ee;
}
}
}
//結果
Exception in thread "main" java.io.IOException: IOExceptionが発生!!
at SampleProgram.main(SampleProgram.java:21)
自作する
用意されていない例外を自分で作成する場合は、Exceptionクラスを継承する例外クラスを作る。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
class myException extends Exception{
myException(String msg) {
super(msg);
}
}
public class SampleProgram {
public static void main(String[] args) throws Exception {
try {
File file = new File("C:\\test3.txt");
FileReader fr = new FileReader(file);
BufferedReader bfr = new BufferedReader(fr);
String ss = null;
while((ss = bfr.readLine()) != null) {
System.out.println(ss + "を読み込みました");
}
bfr.close();
}catch(Exception e) {
e.printStackTrace();
throw new myException("thorwしました");
}
}
}
// 結果
java.io.FileNotFoundException: C:\test3.txt (指定されたファイルが見つかりません。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileReader.<init>(FileReader.java:72)
at SampleProgram.main(SampleProgram.java:19)
Exception in thread "main" myException: thorwしました
at SampleProgram.main(SampleProgram.java:29)
コンストラクタ
基本
アクセス修飾子 クラス名 (引数型 引数) {
// なにか処理
}
継承関係のある場合
コンストラクタは継承されない。
//親クラス
class p{
p(){
System.out.println("親のコンストラクタ1");
}
p(int x){
System.out.println("親のコンストラクタ2");
}
}
//子クラス
class c extends p{
}
public class SampleProgram {
public static void main(String[] args) throws Exception {
c cc = new c(10);
c cc = new c();
}
}
c cc = new c(10);
なら
「コンストラクターc(int)は未定義です」のコンパイルエラー
c cc = new c();
で
「親のコンストラクタ1」が表示される
親のコンストラクタ(引数なし)が継承されているかに見せかけて
子クラスになにも宣言されてないので、コンパイラによって自動的にデフォルトコンストラクタが追加されたらしい。
ソース上ではわからないがこんな感じで、親のコンストラクタを呼ぶようになっているらしい
class c extends p{
c(){
super();
}
}
親と子はセット??
子に明示的にコンストラクタを追加してみたが、なぜか親のコンストラクタも呼ばれた。
class p{
p(){
System.out.println("親のコンストラクタ1");
}
p(int x){
System.out.println("親のコンストラクタ2");
}
}
class c extends p{
c(){
System.out.println("子のコンストラクタ1");
}
}
public class SampleProgram {
public static void main(String[] args) throws Exception {
c cc = new c();
}
}
// 結果
親のコンストラクタ1
子のコンストラクタ1
結局、子クラスのインスタンスが生成されたときに、もちろん、子クラスのコンストラクタが実行される。が、それより先に親クラスの引数なしのコンストラクタを勝手に呼ぶらしい。
ソース上では見えないが、こういうことらしい。
class c extends p{
c(){
super();★コンパイラによって勝手に付けられる
System.out.println("子のコンストラクタ1");
}
}
むむ。。。知らないとはまりそう。。
その他
スニペット(snippet)
丸暗記したりコピペで流用できる構文のこと
System.out.printlnを少しでも省略したい・・
import static java.lang.System.*;
public class SampleProgram{
public static void main(String[] args) {
out.println("hoge");
}
}