javac:编译器,将Java源代码编译成字节码。
java:字节码解释器,直接从类文件执行Java应用程序字节代码。
一个一个对象问题会很复杂,故着眼于对象的类型建立模型,并把类型简称成类(class)
class A{
int i;//数据成员
int j;
}
class test{
public static void main(String[] args)
{
A aa = new A();//(A *)malloc(sizeof(A));动态分配
//new A(); 在堆中动态分配了一块区域,被当作了A 对象
//a本身的内存是在栈中分配的
//堆中内存的地址赋给了aa
//aa指向堆中的内存,aa代表了堆中的内存
//内存=堆内存heap new出来的东西
//+栈内存stack 局部变量 在栈中的东西系统自动释放
//data segment
//code segment
//aa.i, aa.j 代表aa这个静态指针变量指向的动态内存中的A对象
//aa只占四个字节,存放事物的地址,第一个字节的地址
aa.i = 10;
aa.j = 20;
System.out.println("%d %d",aa.i,aa.j);
}
}
对象创建过程:
Employee li4 = new Employee("Lis", 29,’f’, 4477.77);
以上过程中实现了:
① 声明一个引用(reference)
向编译器注册一个类对象的名字
② 操作符new为各成员变量分配存储空间,并自动初始化为变量类型的默认值;
③ 调用构造方法显式进行有关成员变量的初始化;
④ 返回对象的引用。
构造器也是一种特殊的方法(method),用于类创建对象时的属性初始化
定义:
注意事项:
返回值不能作为是否构成函数重载的依据
//参数不同的构造器
Employee();
Employee(String name);
Employee(String name, int age, char sex);
Employee(double baseSalary);
Employee(String name, int age, char sex, double baseSalary);
当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值
局部变量编译器是不会自动进行初始化的,java要求所有的局部变量在使用之前都必须的初始化
在用new新创建对象时,首先会对该对象的实例变量赋予默认初值,之后才调用构造器
表示前面出现过的变量重载
this是特殊的引用,代表当前对象,用来区分参数名和属性名
一个对象只含有属性的空间,n个对象公用 一份方法的拷贝
class A{
public int i;
public A(int j)
{
i = j;
}
public void show()
{
System.out.printf("i=%d", this.i);
//this代表的是当前正在调用show方法的对象
}
}
public class test
{
public static void main(String[] args) {
A aa1 = new A(10);
A aa2 = new A(20);
aa1.show();
aa2.show();
}
}
静态成员属于类本身,而不是属于某个对象,即可以被类的所有对象所共用。static放在变量前表明该属性是各个对象公用的。
静态成员分为
static属性i是属于类本身,或者讲没有对象,我们仍果然可以通过类名的方式访问static属性
通过类名只能访问一个类中非私有静态成员
私有静态成员你也不可以通过对象名访问
static方法也是属于类的
一个类的属性可以是是个类对象(类之间的包含关系)
静态变量存储在静态存储区(即方法区)
任何方法都可直接引用。不可用this引用
静态方法只能访问类的静态成员
类内部访问控制符是透明的,所有的成员可以互相访问;访问控制符是针对外部访问而言的
外部访问的方式:
Java以类作为编译单元
包的声明:package 包名
包名.类名
同一个包中,类名必须唯一;不同包中的类名可以存在相同的情况。
说明:
class SubClass extends SuperClass
{
}
1.子类内部可以访问父类非私有的成员
2.通过子类对象名只能放为从父类继承过来的非私有成员
私有属性、私有方法不能被继承。私有不能被继承,私有物理上已经被继承过来,只不过逻辑上程序员不能去访问它。因此继承必须慎重,否则会导致内存浪费。
Java只支持单继承,不允许多重继承
继承可以有多层继承,即某一个类可以继承某一个类的子类
子类可以继承父类所有的成员变量和成员方法,但子类永远无法继承父类的构造方法
如果子类对父类的方法不够满意时,就应该重写方法。
方法重写的条件:
利用多态可以实现,同一段代码做不同事情
一个父类引用既可以指向父类对象,也可也指向子类对象
它可以根据当前时刻指向的不同,自动调用不同对象的方法,这就是多态
注意事项
子类对象可以直接赋给父类引用,但父类对象在任何情况下都不可以直接赋给子类引用,因为子类是父类的一种,但父类不是子类的一种。
通过父类引用只能访问子类对象从父类继承过来的成员
通过父类引用不能访问子类对象所特有的成员
class A
{
public void f()
{
System.out.printf("AAAA\n");
}
}
class B extends A
{
public void f()
{
System.out.printf("BBBB\n");
}
public void g()
{
}
}
public class TestPoly
{
public static void main(String[] args)
{
A aa = new A();
//aa是父类引用
B bb = new B();
//bb是子类引用
aa.f();
bb.f();
aa = bb;
//把bb当做aa来看待,因为子类可以当做父类来看待,所以本语句ok
bb = aa;
//把aa当做bb来看待,因为父类不能被当做子类看待,所以本语句error
//狗狗可以当做动物看待,但动物不可以当做狗来看待
aa.f();//BBBB 同样的代码语句做不一样的事情
//通过父类引用只能访问子类对象从父类继承过来的成员
//aa.g(); //error通过父类引用不能访问子类对象所特有的成员
//向下造型 强制类型转换
B bb2 = (B)aa;
//only when 父类引用本身指向的就是一个子类对象时,才可以把父类引用强制转化为子类引用
}
}
向上造型(upcasting)
向下造型(downcasting)
不能造对象
abstract class A//含有抽象方法的类必然是抽象类
{
abstract void f();//没有方法体的方法叫做抽象方法
//抽象方法要求末尾必须得加分号,前面必须得加abstract
//只给出方法头,而不给出具体代码方法
}
abstract class B//抽象类不一定包含抽象方法
{
public void g(){
}
}
一个抽象类通常都含有抽象方法
只要含有抽象方法的类一定是抽象类
abstract class A
{
abstract public void f();
}
class B extends A
{
public void f()
{
}
}
public class
{
public static void main(String[] args)
{
}
}
不可以定义抽象类对象,但是抽象类可以实现多态。
abstract class A
{
abstract public void f();
}
abstract class B extends A
{
System.out.println("BBBB");
}
public class TestAbstract
{
public static void main(String[] args)
{
A aa = new A();
//error 抽象类无法创造对象
B bb = new B(); //OK
b.f(); //OK
A aa;//ok 可以定义一个抽象类的引用,但是不可以定义一个抽象类的对象
aa = bb;
aa.f();
}
}
整个类
类中的若干个属性
类中的若干个方法
final class A
{
}
class B extends A //error final修饰类表示该类不能被继承
{
}
class TestFinal_1{
public static void main(String[] args)
{
}
}
class A
{
final public int b;
//error 常变量必须被赋值(默认值也不算是真正的赋值),之后也不能被改变
//相当于C语言的static 增加程序安全性
final public int i //= 10;
public A//构造器一定会被调用,所以可以实现赋值的最终效果
{
i = 22; //如果上面i=22报错,只能赋值一次
}
public void f()//方法不一定被调用
{
i = 22; //error 无法为最终变量i指定值
}
}
class TestFinal_2{
public static void main(String[] args)
{
}
}
final class A
{
final public void f()
{
System.out.println("AAAA");
}
}
class B extends A //final方法只能被继承不能被重写
{
public void f()
{
System.out.println("BBBB");//final方法重写error
}
}
class TestFinal_3{
public static void main(String[] args)
{
}
}
[public] interface interfaceName [extends SuperInterfaceList]
{
//一个接口可以继承多个接口列表
//但是一个类只能继承一个父类,即只能有一个父亲
//常量定义和方法定义
}
接口中定义的属性必须是public static final类型的
接口中定义的方法必须是public abstract类型的
interface It
//接口由关键词interface引出
//其前可以使用public或abstract,也可以什么都不写(默认public),但一定不可以使用private修饰
{
public static final int i = 20;
public abstract void f;
public void(); //接口方法不能带有主体
}
interface It2
{
int i = 20;//修饰符可以部分或全部省略
void f(); //省略后代表的含义一致,因为这是强制的
}
// class A extends It//error 类不能继承接口,类可以继承类
abstract class A implements It //实现接口里面所有的成员变量和成员方法
{
public void f()
{
System.out.println("i = %d",i);
}
}
abstract class B //抽象类不强制拥有抽象方法
{ public void f()
{
}
}
class TestInterface_1{
public static void main(String[] args)
{
}
}
interface It
{
void f();//默认public abstract
}
class A implements It
{
//void f() //不能重写 形参一样 函数名一样 访问权限值需更高
//重写接口方法时public不能省
public void f()
{
System.out.println("AAAA");
}
public void g()
{
}
}
class TestInterface_2{
public static void main(String[] args)
{
int i;
It it;
it = new A();//接口是抽象的,但可以定义一个实现该接口的对象,把这个对象的地址发送给接口来引用,通过接口的引用可以调用这个对象指向的真正的成员
//多态+接口
it.f();
it.g();//通过接口的引用只能调用从父类继承过来的成员,不能调用子类所特有的
//It it2 = new It();//error It是抽象的:无法对其进行实例化。即抽象类不能创造对象
}
}
class A{
int i;
public void show()
{ System.out.printf("show --> %d\n",i);
//此刻的i是属性,此时的i等价于this.i
}
public void f()
{
int i; //这里的i和属性i没有冲突
System.out.printf("f --> %d\n",i);//error 因为i是局部变量,Java要求局部变量在使用前必须被赋初始值
}
}
枚举(enumerate)
public enum Color{red,yellow,blue,white,black};
==
或equals()
进行比较判断是否相等泛指任何类型或多种类新给,用于在设计时无法确定的情形
类名<具体类型名> 引用名 = new类名<具体类型名>();
[访问权限] <泛型标识>返回类型 方法名(泛型标识 参数名){}
集合就是将若干用途、性质相同或相近“数据”组合而成的一个整体
容器一定是类,类不一定是容器
public interface Collection
int size()
boolean isEmpty()
boolean contains(Object o)
boolean containsAll(Collection<?> c)
boolean add(Object o)//把o添加到当前集合中,插入成功返回true
boolean addAll(Collection<? Extends E> c)
boolean remove(Object o)
boolean removeAll(Collection<?> c)
boolean retainAll(Collection<?> c)
Iterator<E> interator()
boolean equals(Object o)
int hashCode()
void clear()
Object{} toArray() //容器不是数组,不能通过下标的方式去访问,只有数组才可以通过下标来访问
<T> T{} toArray(T[] a))
List是Collection的子接口,其定义如下:
public interface List
E set(int index,E element)
E get(int index) //返回给定位置index处的元素
E remove(int index)
void add(int index, E element)
boolean addAll(int index,Collection<?extends E> c)
int indexOf(Object o)
int lastIndexOf(Object o)
List Iterator<E> listIterator()
List<E> subList(int fromIndex,int toIndex)
Set是Collection的子接口,其定义如下:
public interface Set
Iterator接口用统一的方式对集合中的各个元素进行遍历
Iterator接口的对象又称为迭代器,利用该对象可以方便的便利容器中的元素
所有实现了collections街廓的容器类都有一个iterator()方法
boolean hasNext()
:判断当前游标的后面是否还有下一个元素
next()
:先返回当前游标的下一个元素,然后游标后移一个位置。
remove()
:删除最近返回的当前元素。先调用一次next()方法之后才能调用一次remove方法,不推荐使用
public static boid showCollection(Collection c)
{
Iterator it = c.interator();
while(it.hasNext())
System.out.println(it.next());
}
for (类 元素名 :聚集名) {
…
}
Map映射是一种把键对象和值对象进行映射的集合,它的每一个元素都包含一对键对象和值对象
public interface Map
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
boolean equals(Object o)
Set<K> keySet()
Set<Map.Entry<K,V>>entrySet()
V get(Object key)
V put(K key,V value) //different from add(only 1 element)
//根据key计算出存储位置,然后把value存入此位置时,如果该位置已有元素则覆盖它
//该方法返回覆盖之前的元素对象的值,如果以前此位置为空,则返回null
V remove(Object key)
int size()
int hashCode()
void clear()
void putAll(Map<? Extends K,? extends V>t)
Collection<V> values()
colleaction接口的实现类,如ArrayList、LinkedList本身并没有提供排序、倒置、查找等方法,这些方法是由collections类实现的,该类有很多public static方法,可以直接对collection接口的实现类进行操作
程序中出现的问题是无法通过逻辑判断来解决的
Exception e
是一个大的父类
ArithmeticException
:数学异常。ArrayIndexOutOfBoundsException
:数组下标越界异常。ClassCastException
:类型转换异常。IllegalArgumentException
:非法参数异常。IndexOutBoundsException
:下标转换异常。IOException
:输入输出流异常NullPointerException
:空指针异常。UnsupportedOperationException
:不支持的操作。class A
int divide (int a, int b)// add sub minus multiply positive nagetive
{
int m;
m = a/b;
return m;
}
}
public class TsetExcep_1{
public static void main(String[] args)
{
A aa = new A();
try{
aa.divide(6,2);//可能会出错的代码
}
catch(ArithmeticException e)//e来接收try语句中抛出的异常对象 让catch捕获
{
e.printStackTrace();//可以简单理解为输出该异常的具体信息;
System.out.printl("除零错误,你的程序出错啦!除数不能为零");
}
System.out.printl("llalallallallal");
}
}
public class TsetExcep_2{
public static void main(String[] args)
{
int i;
Scanne sc = new Scanner();
try{
i = sc.nextInt();
System.out.printf("i = %d\n", i);
}
catch(InputMismatchException e)
//无法获取用户到底输入的是什么,所以我们只能用try catch实现异常捕获,而不是用if else
{
System.out.printl("输入数据不合法,程序被终止!");
}
class A
int divide (int a, int b){
int m;
m = a/b;
return m;
}
public void f()
{
g();
}
public void g()
{
divide(6,0);
}
}
public class TsetExcep_3{
public static void main(String[] args)
{
try{
new A().g();//可能会出错的代码
}
catch(Exception e)
{
e.printStackTrace();//可以简单理解为输出该异常的具体信息;
}
}
}
import java.io.*
class A{
public void f() throws IOException //throws再抛 不处理
{
throw new IOException();//throw 抛无异常
//必须处理的异常
}
public void g()
{
throw new ArithmeticException();
//可不处理的异常
}
}
public class TsetExcep_4{
public static void main(String[] args) //throws IOException
{
A aa = new A();
try{
aa.f();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
要么自己try catch 要么就甩锅给调用者try catch
import java.io.*
class A{
int divide (int a, int b){
int m;
m = a/b;
return m;
}
}
public class TsetExcep_5{
public static void main(String[] args)
{
try{
A aa = new A(6,2);
}
catch(ArrayIndexOutBoundsException e)
{
e.printStackTrace();
}
finally
{
System.out.printf("wuuw");
}
}
}
throw 用来抛出异常;格式throw new 异常名(参数)
假设f方法抛出了A异常,则f方法有两种方式来处理
throws A
try{...} catch(){ ...}
要抛出的异常必须得是Throwable的子类
import java.io.*
class B extends Throwable
{
//extends Throwable 去掉报错
//自定义异常
}
class A{
public int divide (int a, int b){
int m;
m = a/b;
return m;
}
}
public class TsetExcep_6{
public static void main(String[] args)
{
}
}
import java.io.*
class DivisorIsZeroException extends Exception
{
//extends Throwable 去掉报错
//自定义异常
public DivisorIsZeroException(String name){
super(name);
}
}
class A{
public int divide (int a, int b) throws DivisorIsZeroException
{
int m;
if(0==b)
throw DivisorIsZeroException("除数不能为零!");
else
m = a/b;
return m;
}
}
public class TsetExcep_7{
public static void main(String[] args)
{
A aa = new A();
try{
aa.divide(6,0);
}catch(Exception e)
{
e.printStackTrace();
}
}
}
子类异常抛出的范围
class A extends Exception
{
}
class B extends Exception
{
}
class C extends Exception
{
}
class M
{
void f() extends A, B
{
}
}
class N extends M
{
void f() throws A,B //子类重写父类的f方法
{
//可以throws A或B,也可以throws A,B,但不可以throws C
}
}
class Test
{
public void k(M mm){//多态的运用
try{
mm.f();
}
catch(A aa){
}
catch(B bb){
}
}
}
class TestExtendExce
{
public static void main(String[] args)
{
M m = new M();
N n = new N();
}
传统的ifelse语句无法对想不到的错误已经处理,而异常处理有很多优势:
Java的字符串使用Unicode字符码体系,一个字符占用2B。
这个体系不同于ASCII字符码,涵盖了几乎所有语言会出现的字符。
用十六进制编码表示为\u0000~\uFFFF
,其中\u前缀标志着这是一个Unicode值
\u0061代表字符a
b. String (String original)
:用字符串常量创建字符串对象。
a. String (char[] value)
:用char数组创建字符串对象。
a. String (char[] value,int offset, int count)
:用char数组中从下标offset开始的count个字符创建字符串对象。
b. int compareTo (String anotherString)
:当前字符串比anotherString大,返回正整数;小,返回小于0的整数;相等,返回0。比较的原则:在字母序中,后面的比前面的大;小写的比大写大.。
a. int compareToIgnoreCase (String anotherString)
:忽略大小写,比较两字符串大小。
b. boolean equals (Object anObject)
:当前字符串对象与anObject有相同的字符串,则返回true;否,则返回false。这个方法对于字符大小写敏感。
a. boolean equalsIgnoreCase (String anotherString)
:同equals (),但忽略大小写。
a. boolean startWith (String prefix)
:判断当前字符串是否以prefix开始。
b. char charAt (int index)
b. int indexOf (char ch)
a. int indexOf (char ch, int fromIndex)
b. int indexOf (Sting str)
a. int indexOf (Sting str, int fromIndex)
a. int lastIndexOf (……)
a. String concat (String str):返回当前字符串后追加str后的新字符串。
b. String replace (char oldChar, char newChar):在当前字符串中,将字符oldChar替换为newChar。
a. String replaceAll (String regex, String replacement):在当前字符串中,将字符串regex 替换为replacement。
b. String substring (int beginIndex):返回当前字符串从beginIndex开始的尾子字符串。
b. String substring (int beginIndex, int endIndex):返回当前字符串中从beginIndex开始到endIndex的子字符串。
b. String toLowerCase ():将当前字符串全部转换为小写。
b. String toUpperCase ():将当前字符串全部转换为大写。
class A //默认每个类都使用object作为超类
{
}
public class TestObject
{
public static void main(String[] args)
{
A aa = new A();
System.out.print("%s", aa.toString());
//object类下面带有toString方法
}
}
空的A类得到的返回值是AA对象在堆里面内存地址的16进制表示
class A //默认每个类都使用object作为超类
{
public String toString() //方法的重写
{
return "重写后的返回值";
}
}
public class TestObject_1
{
public static void main(String[] args)
{
A aa = new A();
System.out.print("%s", aa.toString());
}
}
基本类型向字符串类型的转换
基本类型与字符串进行“+”运算,运算结果为字符串类型
class Dian
{
int x, y;
public Dian(int x, int y)
{
this.x = x;
this.y = y;
}
public String toString() //方法的重写
{
return "[" + x + "," + y+ "]";
}
}
public class TestPoint
{
public static void main(String[] args)
{
Dian d = new Dian(1,2);
//申明一个对象时会调用这个对象的构造函数(only 1)
System.out.print("%s", d);
//若未重写返回d对象所在类Dian在toString方法下的内存地址
System.out.print("%s", aa.toString());
}
}
class A
{
public int i;
public A(int i)
{
this.i = i;
}
}
public class TestStringEquals_1
{
public static void main(String[] args)
{
A aa1 = new A(2);
A aa2 = new A(2);
System.out.println( aa1.equals(aa2)); //false
//for same 内存,方得true
if(aa1 == aa2)
System.out.println( "aa1和aa2相等");
else
System.out.println( "aa1和aa2不相等");
}
}
class A
{
public int i;
public A(int i)
{
this.i = i;
}
public boolean equals(Object ob)
{
A aa = (A)Obj; //向下造型
if (this.i == aa.i)//当前对象的i和obj代表的i相等
return true;
else
return false;
}
}
public class TestStringEquals_2
{
public static void main(String[] args)
{
A aa1 = new A(2);
A aa2 = new A(2);
System.out.println( aa1.equals(aa2)); //true
//this aa1
//obj aa2
}
}
归属于对象out的一个方法,而这个out是System类的一个static成员(属性)
System.out.println();
System.out.printf();
public class TestPrint
{
public static void main(String[] args)
{
int i, j, k;
i = 1;
j = 2;
k = 3;
System.out.printf("%d的值+%d的值是%d\n", i, j, k);
System.out.println(i+"的值+"+j+"的值是"+k);
//隐式地将其后面用“+”连接的任何数据转换为字符串连接在前面的字符串后面
int m = 1234;
System.out.println(m);
System.out.printf("%d",m);
System.out.printf("%d用十六进制表示的结果是:%#X",m,m);
System.out.println(m+"用十六进制表示的结果是:OX"+(Integer.toHexString(m).toUpperCase());
}
}
String类对象一旦创建就不可更改
如果经常对字符串内容进行修改而使用String的话,就会导致即消耗空间又消耗时间
String s1 = "abc";
String s2 = "123";
String s1 = s1 + s2;
上述代码并没有在s1的基础上继续增加s2的内容,而是新创建一个字符串空间存入相应的内容
StringBuffer对象的内容是可以修改的,且含有大量修改字符串的方法
public StringBuffer()
创建一个空的没有任何字符的StringBuffer对象
public StringBuffer(int capacity)
创建一个不带字符,但具有初始容量的字符串缓冲区
public StringBuffer(String str)
创建一个包含str对象相同的字符序列
数据类型 数组名[] = null;
prefer数据类型[] 数组名 = null;
因为可以一看过去就知道这是数组
数组名 = new 数据类型[元素个数];
必须指明:
public class TestArray
{
public static void main(String[] args)
{
//方式1
//动态初始化:先声明,再赋值
int[] arr1;
arr1 = new int[3];
arr1[0] = 0;
arr1[1] = 1;
arr1[2] = 2;
showArr(arr1);
System.out.println("*************");
//方式2
//静态初始化:在使用new操作符分配存储空间的同时进行初始化
int[] arr2 = new int[]{0,1,2};
showArr(arr2);
System.out.println("*************");
//静态初始化时可以不使用new操作符
int[] arr3 = P{0,1,2};//both ok
showArr(arr3);
System.out.println("*************");
}
public static void showArr(int[] arr)
{
for(int i = 0; i<arr.length; ++i)
{ //length是属性不是方法()
System.out.println(arr[i]);
}
}
注意:
在静态初始化时不可以写出数组维表达式,因为编译器完全可以通过初始化值的个数自动计算出需要分配发存储空间的大小,无须画蛇添足。
for (循环变量类型 循环变量名称: 要被遍历的集合) 循环体
int[] a = null;
a = new int[3];
for(int e:a) {
System.out.println(e);
}