三种注释: // /* */ /** */
输出控制符 | 针对的数据类型 |
---|---|
%d | int, long int, short, byte |
%x, %#X, %X, %#X | int, long int |
%c | char |
%f | float, double |
%s | String |
在java中打印语句有三种,分别是println,print,printf,三者之间有区别
//十六进制输出控制符
class TestHex
{
public static void main(String[] args)
{
int i = 253;
System.out.printf("%x\n", i); // 输出fd
System.out.printf("%X\n", i); // 输出FD
System.out.printf("%#x\n", i); //输出0xfd
System.out.printf("%#X\n", i); //输出0XFD
}
}
一个常量整数默认是int类型,如果数字过大,则必须要在末尾加L,否 则会出错
一个实数默认是double类型,如果希望一个实数是float类型,可以在数字后面加f(F)
将一个double类型数值赋给float类型变量,编译会报错
float x = 2.2; //error
float x = 2.2f; //OK
字符常量必须用单引号括起来,Java中字符和字符串都用Unicode编码表示,在Unicode编码中一个字符占两个字节
反斜线 '\\'
退格 '\b'
回车 '\r'
制表符 '\t'
换行 '\n'
单引号 '\''
//字符常量的'\uxxxx'表示
public class A
{
public static void main(String[] args)
{
char ch1 = '中';
char ch2 = '\u4e2d'; //'\uxxxx'表示十六进制的xxxx所对应的Unicode编码下的字符
System.out.printf("%c %c\n", ch1, ch2); //运行结果:中 中
}
}
用boolean表示,不能写成bool
布尔型数据只有两个值true和false,且他们不对应与任何整数值
布尔型变量的定义如:boolean b = true;
布尔型数据只能参与逻辑关系运算:&& || == != !
注意:if while for 中进行真假判断时只能使用逻辑表达式
在把容量大的类型转换为容量小的类型时必须使用强制类型转换
整形、实型、字符型数据可以混合运算。运算中,不同类型的数据先转换为同一类型,然后进行运算,转换从低级到高级:
低----------------------------------->高
byte -> char -> int -> long -> float -> double
算术运算符:+ - * / %
关系运算符: > >= < <= != ==
逻辑运算符: ! && ||
赋值运算符:= += * = /= %=
位运算符:& | ~ ^
+
可以表示数值的相加,可以表示字符串的联接,如:“123” + “abc” 的结果是“123abc”,还能把非字符转换成字符串,如:“x” + 123;的结果是“x123”
System.out.println('a' + 1); //98
System.out.println("" + 'a' + 1); //a1
除法/的运算结果和运算对象的数据类型有关,若两个数都是int,则商就是int,若商有小数,则截取小数部分;若两个对象中有一个或两个都是浮点型数据,则商也是浮点型,不截取小数部分
如:16/5 == 3, 16/5.0 == 3.20000, -13/4 == -4, -13/-3 == 4
Java中允许取余运算符的被除数和除数是实数,但所得余数的正负只和被除数相同
double x = 1 % -0.3
System.out.println(x); // 0.10000
当&& 左边表达式为假时,&&右边的表达式是不执行的。因为无论&&右边的表达式为真还是为假,整个表达式都为假
同理,当||表达式左边为真时,||右边的表达式是不会执行的
一个0或一个1就代表一位,一位只能存储一个0或一个1,8位代表一个字节,位用bit表示,字节用byte表示
1 & 1 = 1, 1& 0 = 0, 0 & 0 0, 0 & 1 = 0
1 | 1 = 1, 1 | 0 = 1, 0 | 0 = 0, 0 | 1 = 1
~ 1 = 0, ~ 0 = 1
int i = 11; // 0000 1011
int j = -2; // 0000 0010 -> 1111 1101 -> 1111 1110
System.out.printf("%d\n", i & j); //10, 0000 1010
>>>
无论最高位是0还是1,左边移空的改为都补0<<和<<<
同理运算表达式书写规则:
private
的不能再外部访问自顶向下的设计模式
分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现
以算法为核心,自顶向下设计,要求一开始必须对问题有很深的了解
将大问题转化为若干小问题来求解
表现形式:用函数来作为划分程序的基本单位
直接面向问题
易于掌握与理解,符合人们的思维习惯
对于需求明确,规模不大,变动较小的问题非常适合
数据与操作分离开,对数据与操作的修改变得很困难
数据的安全性得不到保证
程序架构的依赖关系不合理。main函数依赖于子函数,子函数又依赖于更小的子函数;而子函数往往是细节的实现,这些实现是经常变化的,造成的结构就是:程序的核心逻辑依赖于外延的细节,一个细节上的小改动,会引起一系列的变动
对于“需求不明确、变动较大、规模很大的问题”,显得力不从心
确定该问题由哪些事物组成,先用类模拟出该事物,通过类间接的解决问题。自下而上设计,从问题的一部分着手,一点一点的构建出整个程序
表现形式:用类来作为划分程序的基本单位
对于需求不明确、变动较大、规模很大的问题非常适合
对于“需求明确、规模不大、变动较小的问题”则显得十分累赘
面向对象的三个基本特征:封装、继承、多态
把一类事物的静态属性和动态可以执行的操作组合在一起所得的这个概念就是类
类是抽象的,用来模拟一类事物,是一个概念。一旦被定义,类的概念就永远存在了。
class Person
{
int age; //age是类的属性,也叫类数据成员,也叫字段,也叫域
void shout() //shout是方法,也叫类的成员函数,shout方法可以直接访问同一个类中的age变量
{
System.out.println("my age " + age);
}
}
类的一个个体,是具体的,实实在在存在的事物。生命周期是短暂的,会生成和消亡。
类与对象:如果将对象比作汽车,那么类就是汽车的设计图纸
//类对象实例1
class A
{
int i;
int j;
}
public class TCS
{
public static void main(String[] args)
{
A aa1 = new A(); // 相当于C语言中(A *)malloc(sizeof(A));
//new A(); 在堆中动态分配一块区域,被当做了A对象
//aa本身的内存是在栈中分配的,堆中内存的地址赋给了aa
//aa指向堆中的内存,aa代表了堆中的内存
//aa.i 代表:aa这个静态指针变量所指向的动态内存中的A对象的i这个成员
//aa.j 代表:aa这个静态指针变量所指向的动态内存中的A对象的j这个成员
aa.i = 10;
aa.j = 20;
System.out.printf("%d, %d\n", aa.i, aa.j); //输出10,20
}
}
//类对象实例2
class A
{
int i = 10;
int j = 20;
}
public class TCS
{
public static void main(String[] args)
{
A aa1 = new A();
A aa2 = new A();//在堆内存中动态分配了两块区域,aa1和aa2分别指向这两块区域
}
}
//类对象实例3
class A
{
int i = 10;
int j = 20;
}
public class TCS
{
public static void main(String[] args)
{
A aa1 = new A();
A aa2 = aa1;
aa1.j = 99;
System.out.printf("%d\n", aa2.j); //99
}
}
类的访问控制符有四种:public、protect、默认(不加任何修饰符default)、private
在一个类的内部,所有的成员可以相互访问,访问控制符是透明的;访问控制符是针对外部访问而言的
外部访问包括两种方式:通过类名访问类内部的成员,通过类对象名访问类内部成员
在一个类的内部,所有的成员可以相互访问,访问控制符是透明的
在一个类的外部:通过 类对象名.私有成员名 的方式是无法访问该对象中的私有成员的,这样写编译时会出错
当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值
成员变量类型 | 初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0D |
char | ‘\u0000’ |
boolean | false |
All reference type(所有引用类型) | Null |
int k;
System.out.printf("%d\n", k);//报错,局部变量编译器是不会自动进行初始化的,java要求所有的局部变量在使用之前都必须初始化
//一旦编程者为类定义了构造方法,系统就不再提供默认的构造方法了
class A
{
private int i;
public A()//如果将这个定义注释,程序就回报错
{
}
public A(int j)
{
i = j;
}
}
public class TestConst_4
{
public static void main(String[] args)
{
A aa1 = new A();
A aa2 = new A(1);
}
}
class A
{
public int i;
public A(int j)
{
i = j;
}
public void show()//this代表的是当前正在调用show方法的对象
{
System.out.println("i= " + i);//i可以换成this.i
}
}
class M
{
public static void main(String[] args)
{
A aa1 = new A(5);//aa1和aa2在内存中分别有各自的数据成员i
A aa2 = new A(8);
aa1.show();//但是aa1和aa2共用show()方法,show方法如何知道输出的i应该是哪个对象中的i
aa2.show();//实际上每个非static方法中都隐含这一个this指针,指向当前正在调用该方法的对象
}
}
class A
{
private int i;
public A(int i)
{
this.i = i; //this代表当前时刻正在创建的对象
}
public void show()
{
System.out.printf("%d\n", this.i); //this代表正在调用show方法的对象,this可以省略
}
}
public class TestThis
{
public static void main(String[] args)
{
A aa1 = new A(100);
aa1.show();
}
}
//本程序证明:A类的多个对象共用一个static属性i
class A
{
public static int i = 10;
public void show()
{
System.out.printf("%d\n", i); // 20
}
}
class M
{
public static void main(String[] args)
{
A aa1 = new A();
A aa2 = new A();
A aa3 = new A();
aa1.i = 20;
aa2.show();
System.out.printf("%d\n", aa3.i); //20
}
}
//本程序证明了:static属性i是属于类本身的,或者讲:没有对象,我们仍然可以直接通过类名的方式访问该类内部的static属性
//static方法f同理
class A
{
public static int i = 10;
public static void f()
{
System.out.printf("2020年6月");
}
}
class TestStatic_2
{
public static void main(String[] args)
{
System.out.printf("%d\n", A.i); //10
A.f();
A aa = new A();
aa.f();
System.out.printf("%d\n", aa.i); // 10
//static属性和方法虽然属于类本身,虽然可以通过类名的方式访问,
//但是static属性和方法很明显也属于类对象,当然也可以通过类对象名的方式访问
}
}
//本程序证明了:
//只有非private的static成员才可以通过类名的方式访问
//static只是表明了该成员具有了可以通过类名访问的潜在特征
//但是否可以通过类名访问,还必须满足一个条件: 该成员必须是非private
class A
{
private static int i = 10;
private static void f()
{
System.out.printf("2020年6月\n");
}
}
class TestStatic_4
{
public static void main(String[] args)
{
//A.f();//error
A.i = 22;//error
}
}
//本程序证明了:
//静态方法不能访问非静态成员
//非静态方法可以访问静态成员
class A
{
private static int i = 10;
public int j = 99;
public static void f()
{
//g(); //error 静态方法不能访问非静态成员
//j = 22; //error
System.out.printf("FFFF\n");
}
public void g()
{
//f(); //OK 说明非静态方法可以访问静态成员
System.out.printf("GGGG\n");
System.out.printf("%d\n", i);
}
}
class TestStatic_5
{
public static void main(String[] args)
{
A aa = new A();
//aa.g();
aa.f();
//A.g(); //error
}
}
class A
{
private int i;
private static int cnt = 0;
public A()
{
++cnt;
}
public A(int i)
{
this.i = i;
++cnt;
}
public static int getCnt()
{
//return 返回的是A对象的个数;
return cnt;
}
}
public class TestStatic_1
{
public static void main(String[] args)
{
System.out.printf("当前时刻A对象的个数是: %d\n", A.getCnt());//0,能够计算A对象的个数
A aa1 = new A();
System.out.printf("当前时刻A对象的个数是: %d\n", A.getCnt());//1
A aa2 = new A();
System.out.printf("当前时刻A对象的个数是: %d\n", A.getCnt());//2
}
}
class A
{
public int i = 20;
private static A aa = new A(); //aa是否是A对象的属性,aa是A对象,也是A的属性
private A()
{
}
public static A getA() //static 一定是不能省略的
{
return aa;
}
}
public class TestStatic_2
{
public static void main(String[] args)
{
A aa1 = A.getA(); // 只生成一个对象,aa1和aa2是相等的
A aa2 = A.getA();
aa1.i = 99;
System.out.printf("%d\n", aa2.i);
if (aa1 == aa2)
System.out.printf("aa1 和 aa2相等\n");//aa1和aa2是相等的
else
System.out.printf("aa1 和 aa2不相等\n");
// A aa1 = new A(); // error 如果A类的构造方法是private的,则new A()就会报错!
// A aa2 = new A(); //同上
}
}
class SubClass extends SuperClass
{
.......
}
利用继承可以较好的模拟出现实世界事物之间的联系
//子类内部可以访问父类非私有的成员,私有成员无法被子类方法访问
//通过子类对象名只能访问从父类继承过来的非私有成员
//总结:私有不能被继承,私有物理上已经被继承过来,只不过逻辑上程序员不能去访问它
//因此继承必须慎重,否则会浪费内存
class A
{
public int i;
protected int j;
private int k;
public void g(){}
private void s(){}
protected void b(){}
}
class B extends A
{
private void m()
{
i = 10;
j = 20;
//k = 30; //error 私有属性不能被继承
g();
b();
//s(); //error 私有方法不能被继承
}
public void f()
{
i = 10;
j = 20;
//k = 30; //error 私有属性不能被继承
g();
b();
//s(); //error 私有方法不能被继承
}
}
class M
{
public static void main(String[] args)
{
B bb = new B();
bb.i = 20;
bb.j = 30;
bb.b();
bb.g();
//bb.s(); //error
//bb.k = 22;
}
}
继承的原则:当B是一个A,让B做A的子类
经验证,通过上述三种方式,父类中的私有成员都不能被访问,因此得出结论:私有成员不能被继承
class A
{
public int i;
protected int j;
private int k;
}
class B extends A
{
private void g()
{
i = 10;
j = 20;
//k = 30; // error
}
}
class Test
{
public static void main(String[] args)
{
//B bb = new B();
//bb.i = 10;
//bb.j = 20;
//bb.k = 30;//error
A.i = 90;
B.j = 10;
//B.k = 100; // error
}
}
super(参数列表)
,不能直接写父类的类名super()
super();
语句,则必须保证该语句是第一条语句,并且必须保证父类有无参地构造函数,否则会出错super();
前提是父类必须有无参地构造函数super(实参);
前提是父类必须有带参地构造函数super(实参列表)
class A
{
A(){
System.out.println("AAAA");
}
A(int i){}
}
class B extends A
{
B(){
super(2); //如果把该语句注释掉的化,则编译器默认的是自动隐藏调用super(); 但如果父类没有无参的构造函数,则会报错
//一个子类的构造函数中只能出现一个 super(....)
System.out.println("BBBB");
}
}
class C extends B
{
C()
{
//int k = 10; //如果该语句生效 则会出错,因为会导致super()语句不是构造函数的第一条语句
super(); //35行 每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有无参的构造函数,那么在编译的时候就会报错。
//super();语句可以写,也可以不写,不写的化,系统会自动调用的
//如果显示写出来的话,编译器要求该语句前面不能加任何语句,也就是说该语句必须保证是第一条语句
// super()也可以改为super(2); 但前提是父类必须有带一个参数的构造函数,否则也会报错
//如果把35行改为 super(2); 编译时就会报错!
System.out.println("CCCC");
}
}
class TestSuper_1
{
public static void main(String[] args)
{
C cc = new C();
}
}
/*
运行结果:
BBBB
CCCC
*/
class A
{
public void f()
{
System.out.printf("AAAA\n");
}
}
class B extends A
{
public void f()//方法重写
{
System.out.printf("BBBB\n");
}
}
class TestOver_1
{
public static void main(String[] args){}
}
class A
{
public int f(int i)
{
System.out.printf("AAAA\n");
}
}
class B extends A
{
//把int改为long编译时会报错
//把public改为iprotected就会报错,
//不能使用比父类中被重写的方法更严格的访问权限
public int f(int i) //重写方法的权限不能低于被重写方法的访问权限
{
System.out.printf("BBBB\n");
}
}
class TestOver_2
{
public static void main(String[] args)
{
B bb = new B();
bb.f(10);//编译器无法确定f方法是父类的还是子类的
}
}
class A
{
public void f()
{
System.out.printf("AAAA\n");
}
}
class B extends A
{
public void f()
{
System.out.printf("BBBB\n");
}
}
class TestPoly
{
public static void main(String[] args)
{
B bb = new B();
bb.f();
A aa = new A();
aa.f();
aa = bb; //aa可以根据它自己当前时刻指向的是A类对象还是A子类对象,
// 而自动决定调用哪个对象的f方法,这就是多态
aa.f(); // (*aa).f();
}
}
class A
{
public void f(){
System.out.printf("AAAA\n");
}
}
class B extends A
{
public void f(){
System.out.printf("BBBB\n");
}
}
class C extends B
{
public void f(){
System.out.printf("CCCC\n");
}
}
class D extends C
{
public void f(){
System.out.printf("DDDD\n");
}
public void g()
{
System.out.printf("GGGG\n");
}
}
class TestPoly_1
{
//m函数可以实现调用整个A类族所有对象f方法的功能
public static void g(aa)
{
aa.f(); //类似于C语言的: (*aa).f();
}
public static void main(String[] args)
{
A aa = new A();
B bb = new B();
C cc = new C();
D dd = new D();
g(aa); // 多态
g(bb);
g(cc);
g(dd);
aa = dd;
aa.g(); // error (*aa).g();
}
}
class A{}
class B extends A{}
public class TestPoly_3
{
public static void main(String[] args)
{
A aa = new A();
B bb = new B();
//bb = aa; //error,父类引用赋给子类引用
//bb = (B)aa; //24行 编译没有错误,但运行时出错! 因为aa指向的是父类对象
A aa2 = new B();
//bb = aa2; //error 永远不可以把父类引用直接赋给子类引用
bb = (B)aa2; //OK 因为aa2 本身指向的就是一个B类对象 所以可以进行强制转化,注意与24行的区别 如果父类引用指向的是个子类对象,则可以通过强制类型转化把父类引用强制转化为子类引用,注意必须强制转化,在Java中无论如何绝对不可能直接把父类引用赋给子类引用的
}
}