关键字:都是小写
特殊:main不是关键字
标识符:就是给类,接口,方法,变量等起名字
组成规则:
英文大小写字母
数字字符
_和$
注意事项:
不能以数字开头
不能是关键字
Java语言中严格区分大小写
常见的命名规则:
见名知意
包:就是文件夹,用于把相同的类名进行区分
全部小写
类或者接口:
一个单词:单词的首字母必须大写
多个单词:每个单词的首字母必须大写
方法或者变量:
一个单词:单词的首字母小写
多个单词:从第二个单词开始,每个单词的首字母大写
常量:
一个单词:全部大写
多个单词:每个字母都大写,用_隔开
举例:STUDENT_MAX_AGE
分类:
字面值常量
自定义常量
字面值常量:
字符串常量:用双括号括起来
整数常量:所有的整数
小数常量:所有小数
字符常量:用单引号括起来的常量
举例:'a'
错误的:'ab'
布尔常量 :true,false
1byte = 8bit
1k = 1024byte
1m = 1024k
1g = 1024m
1t = 1024g
进制转换:
二进制:以0b开头
八进制:以0开头
十六进制:以0x开头
二进制 1 1 1 1 1 1 1 1
十进制 128 64 32 16 8 4 2 1
十进制转二进制
100 = 0b1100100
计算机在操作的时候,都是采用数据对应的二进制的补码来计算的。
原码:符号位 数值位
正数的原码最高位为0
负数的原码最高位为1
例如 +7 , -7
7的二进制是111
+7的原码 0000111
-7的原码 1000111
反码:正数的反码与原码相同,
负数的反码与原码是符号位不变,数值位取反,就是1变0,0变1
+7的反码: 0000111
-7 的反码: 1111000
补码:正数的补码与原码相同
负数的补码是在反码的基础上加1
+7的补码:0000111
-7的补码:1111001
面试题:
题1:byte b1 = 3, b2 = 4, b;
b =b1 + b2;
b = 3+ 4;
那句是编译失败的呢?为什么?
分析:
b = b1+b2;这个是类型提升,所以有问题
b = 3+ 4;常量,先把结果算出来 ,看看是否在byte的范围内,如果在就不报错。
结果:b = b1+b2;是有问题的
因为变量相加,会首先看类型问题,最终把结果复制的也会考虑类型问题
常量相加,首先做加法,然后 看结果是否在赋值的数据类型范围内,如果不是,才报错。
题2:byte b = 130;有没有问题 ?如果我想让赋值正确,可以怎么做?解雇是多少呢?
解:因为byte的范围是: -128到127
而130不在此范围内,所以报错。
可以用强制类型转换
byte b = (byte) 130;
得到结果分析:
要想知道结果是什么,就应该知道是如何进行计算的,我们知道
计算机中数据的运算都是补码进行的,而要得到补码,就要计算出二进制
(1):获取130数据的二进制
10000010
130是个整数,四个字节
00000000 00000000 00000000 10000010
这是 130的原码,也是反码,补码
(2):做截取操作,截成byte类型的
1000001这个结果是补码
(3):已知补码求原码
符号位 数值为
补码: 1 0000010
反码: 1 0000010
原码: 1 1111110
结果是-126
‘a’ 97
'A' 65
'0' 48
从左往右运算
字符串数据和其他数据做+,结果是字符串类型
这里的+不是加法运算,而是字符串连接符
方法重载:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
方法重载特点:
与返回值无关,只看方法名和参数列表
参数列表不同:参数个数不同,参数类型不同
数组:
int[] a = new int[];
右边:为数组分配内存空间
大多使用静态初始化:(还有动态初始化)
int [] arr = new int [] {1,2,3};
简化后:int[] arr = {1,2,3};
java的内存分配:
栈(先进后出)存储局部变量
堆存储new出来的东西
方法区
本地方法区(和系统相关)
寄存器(给CPU使用)
堆内存的特点:
A:每一个new出来的东西都有地址值
B:每个变量都有默认值
byte,short, int.long 0
float , double 0.0
char '\u0000'
boolean false
引用类型 null
C:使用完毕之后就会变成垃圾,但是并没有立即回收。会在垃圾回收器空闲的时候回收
栈内存的数据用完就释放掉
封装:encapsulation
继承:inheritance
多态:polymorphism
成员变量与局部变量:
在类中的位置不同
成员变量在类中方法外
局部变量在方法定义中或者方法声明中
在内存中的位置不同
成员变量:在堆内存
局部变量:在栈内存
生命周期不同
成变:随着对象的创建而存在,随着对象的消失而消失
局变:随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同:
成变:有默认初始化值
局变:没有默认初始化值,必须定义,赋值,然后才能使用
匿名对象:就是没有名字的对象
如:new Student();
匿名对象的应用场景:
1:调用方法,仅仅只调用一次的时候。
调用多次的时候不适合。
匿名对象调用完毕就是垃圾,可以被垃圾回器期回收。:2:
2:匿名对象可以作为参数传递如new StudentDemo.method
(new Student);
private :被private修饰的成员变量和·成员方法只能在本类中访问。
封装:是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式
封装是一个权限修饰符,可以修饰成员变量和成员方法
封装原则:
将不需要对外提供的内容都隐藏起来。
把属性隐藏,提供公共方法对其访问
private 最常见的应用:
把成员变量用private修饰
提供对应的getxxxx()方法和setxxxx()方法
this : 是当前类的对象引用,就是代表当前类的一个对象。
注意:谁调用这个方法,在该方法内部的this就代表谁。
this的场景:
解决局部变量隐藏成员变量
构造方法:
给对象的数据进行初始化
构造方法格式:
方法名与类名相同
没有返回值类型,连void都没有
没有具体的返回值
构造方法注意事项:
如果我们没有给出构造方法,系统会自动提供一个无参的构造方法
如果我们给出了构造方法,系统将不再提供默认的无参构造方法
注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出,建议永远自己给构造方法。
Student s = new Student();在内存中做了哪些事情?
~加载Student.class文件进内存
~在栈内存为s开辟空间
~在堆内存为学生对象开辟空间
~对学生对象的成员变量进行默认初始化
~对学生对象的成员变量进行显示初始化
~通过构造方法对学生对象的成员变量赋值
~学生对象初始化完毕,把对象地址赋值给s变量
变量什么时候定义为成员变量:
如果这个变量是用来描述这个类的信息的,那么,该变量就应该定义为成员变量。
变量的范围是越小越好,因为能及时回收。
static(静态)关键字:
特点:
·随着类的加载而加载
回想main方法
·优先于对象存在
·被类的所有对象共享
距离:咱们班级的学生应该共用同一个班级编号
如果某个成员变量是被所有对象共享的,那么他就应该定义为静态的。
举例:饮水机(用静态修饰)
水杯(不能用静态修饰)
·可以通过类名调用。
其实他本身也可以通过对象调用。
静态修饰的内容一般我们称其为,与类相关的,类成员。
static注意事项:
·在静态方法中是没有this关键字的
理解是:静态是随着类的加载而加载,this是随着对象的创建而存在。
·静态方法只能访问静态的成员变量和静态的成员方法。
静态方法;
成员变量:只能访问静态变量
成员方法:只能访问静态成员方法
非静态方法:
成员变量:可以是静态的,也可以是非静态的
成员方法:可以是静态的成员方法。也可以是非静态的成员方法。
java.lang包中的类不需要导
代码块:在java中,使用{}括起来的代码被称为代码块。
根据其位置和声明的不同,可以分为
局部代码块:局部位置,用于限定变量的生命周期。
构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行构造代码块。
作用:可以把多个构造方法中的共同代码放到一起。
静态代码块:
在类中的成员位置,用{}括起来的代码。只不过是用static修饰了。
作用:一般是对类进行初始化。
面试题:静态代码块 ,构造代码块,构造方法的执行顺序?
静态代码块----构造代码块-----构造方法
静态代码块:只执行一次
构造代码块:每次调用构造方法都执行。
继承:
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
class 子类名 extends 父类名 {}
继承是一把双刃剑。
类与类产生了关系,也有弊端
类的耦合性增强了
开发的原则:低耦合,高内聚
耦合:类与类的关系
内聚:就是自己完成某件事情的能力
java中继承的特点:
·java只继承单继承,不支持多继承
有些语言是支持多继承,格式:extends 类1,类2....
·java中支持多层继承(继承体系)
java中继承的注意事项:
·子类只能继承父类所有非私有的成员(成员变量和成员方法)
·子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
·不要为了部分功能而去继承
什么时候去使用继承呢?
继承其实体现的是一种关系:"is a"。
采用假设法:如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
在子类方法中访问一个变量的查找顺序:
·在子类方法的局部范围找,有就使用
·在子类的成员范围找,有就使用
·在父类的成员范围找,有就使用
·如果还找不到,就报错
this代表本类对应的引用
super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)
用法:
·调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
·调用构造方法
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
·调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
继承中构造方法的关系:
·子类中所有的构造方法默认都会访问父类中空参数的构造方法
·为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。
注意:子类每一个构造方法的第一条语句默认都是:super(...)
如果父类没有无参构造方法,那么子类的构造方法会报错。如何解决呢?
·在父类中加一个无参构造方法
·通过使用super关键字去显示父类的调用父类的带参构造方法
·子类通过使用this去调用本类的其他构造方法
子类中一定要有一个去访问父类的构造方法,否则父类数据就没有初始化
注意:this(...)或者super(..)必须出现在第一条语句上。
如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化
注意:
·成员变量 就近原则
·this访问本类的成员
super访问父类的成员
·子类构造方法执行前默认先执行父类的无参构造方法
·一个类的初始化过程,
先对成员变量初始化
默认初始化
显示初始化
构造方法初始化
package practices;
class Fu {
public int num = 10;
public Fu() {
System.out.println("fu");
}
}
class Zi extends Fu {
public int num = 20;
public Zi() {
System.out.println("zi");
}
public void show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
public class Test2 {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
运行结果是:
fu
zi
30
20
10
一个类的静态代码块,构造代码块,构造方法的执行流程
静态代码块>构造代码块>构造方法
静态的内容是随着类的加载而加载
静态代码块的内容会优先执行
子类初始化之前会先进行父类的初始化
看程序写结果:
package examplee;
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
public class Test1 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
运行结果为:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
子父类的初始化(分层初始化):
先进行父类初始化,然后进行子类初始化
看程序写结果:
package examplee;
class X {
Y b = new Y();
public X() {
System.out.println("X");
}
}
class Y {
public Y() {
System.out.println("Y");
}
}
public class Test2 extends X {
Y y = new Y();
public Test2() {
//super();
System.out.println("Z");
}
public static void main(String[] args) {
new Test2();
}
}
运行结果:
Y
X
Y
Z
注意:
虽然子类构造方法中默认有一个super(),初始化的时候,不是按照那个顺序进行的。而是按照分层初始化进行的。它仅仅表示要先初始化父类数据,再初始化子类数据。
继承中成员方法的关系:
·子类中的方法和父类中的方法声明不一样,这个太简单。
·子类中的方法和父类中的方法声明一样。
通过子类对象调用方法:
·先找子类中,看有没有这个方法,有就使用
·再看父类中,有没有这个方法,有就使用
·如果没有就报错。
方法重载:
本类中出现的方法名一样,参数列表不同的方法。与返回值无关。
方法重写:
子类中出现了和父类中方法声明一模一样的方法。
子类对象调用方法的时候:
先找子类本身,再找父类。
方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容。
方法重写的注意事项:
·父类中私有方法不能被重写
因为父类私有方法子类根本就无法继承
·子类重写父类方法时,访问权限不能更低。最好就一致。
·父类静态方法,子类也必须通过静态方法进行重写
其实这个算不上方法重写,但是现象确实如此,在多态中会解答。
子类重写父类方法的时候,最好声明一模一样。
面试题:
1:方法重写和方法重载的区别?方法重载能改变返回值类型吗?
方法重写:
在子类中,出现和父类一模一样的方法声明现象。
方法重载:
同一个类中,出现的方法名相同,参数列表不同的现象。
方法重载能改变返回值类型,因为它和返回值类型无关。
override:方法重写
overload:方法重载
2:this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。
this:代表当前类的对象印用
super:代表父类存储空间的表示。(可以理解为父类的引用,通过这个东西可以访问父类的成员)
场景:
成员变量:
this.成员变量
super.成员变量
构造方法:
this(...)
super(...)
成员方法:
this.成员方法
super.成员方法
实例:
package examplee;
class Animal {
private String name;
private int age;
private String color;
public Animal() {
}
public Animal(String name,int age,String color) {
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat() {
System.out.println("该吃饭了,不要睡了");
}
}
class Cat extends Animal {
public Cat() {
}
public Cat(String name,int age,String color) {
super(name, age, color);
}
public void playGame() {
System.out.println("猫玩消消乐");
}
}
class Dog extends Animal {
public Dog() {
}
public Dog(String name,int age,String color) {
super(name, age, color);
}
public void lookDoor() {
System.out.println("狗看家");
}
}
public class Test3 {
public static void main(String[] args) {
//测试猫
//方式1
Cat c1 = new Cat();
c1.setName("阿亮");
c1.setAge(3);
c1.setColor("黑色");
System.out.println(c1.getName()+"---"+c1.getAge()+"---"+c1.getColor());
c1.eat();
c1.playGame();
System.out.println("----------");
//方式2
Cat c2 = new Cat("小亮", 4, "白色");
System.out.println(c1.getName()+"---"+c1.getAge()+"---"+c1.getColor());
c2.eat();
c2.playGame();
}
}
运行结果:
阿亮---3---黑色
该吃饭了,不要睡了
猫玩消消乐
----------
阿亮---3---黑色
该吃饭了,不要睡了
猫玩消消乐
final:
最终的意思。常见的是它可以修饰类,方法,变量。
特点:
final可以修饰类,该类不能被继承
final可以修饰方法,该方法不能被重写。
final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。
常量:
字面值常量
自定义常量:
final int x = 10;
final关键字面试题:
final修饰局部变量的问题:
基本类型:基本类型的值不能发生改变
引用类型如(ss = new Student()):引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
final修饰变量的初始化时机
·被final修饰的变量只能赋值一次
·在构造方法完毕前。(非静态的常量)
多态概述:
同一个对象(事物),在不同时刻表现出来的不同状态。
多态的前提:
·要有继承关系
·要有方法重写
其实没有也是可以的,但是如果没有这个就没有意义。
·要有父类引用指向子类对象
父 f =new 子();
多态中的成员访问特点:
·成员变量
编译看左边,运行看左边。
·构造方法
创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化
·成员方法
编译看左边,运行看右边。
·静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
由于成员方法存在重写,所以他运行看右边。
多态的好处:
·提高了代码的维护性(继承保证)
·提高了代码的扩展性(由多态保证)
多态的弊端:
不能使用子类的特有功能。
解决呢?
·创建子类对象调用方法即可(可以,但是很多时候不合理,而且太占内存了)
·把父类的引用强制转换为子类的引用。(向下转型)
对象间的转型问题:
向上转型
Fu f = new Zi();
向下转型
Zi z = (Zi)f;//要求该f必须是能够转换为Zi的
多态的猫狗案列:
package examplee;
class Animal {
public void eat() {
System.out.println("吃饭");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃肉");
}
public void lookDoor() {
System.out.println("狗看门");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void playGame() {
System.out.println("猫玩捉迷藏");
}
}
public class Test1 {
public static void main(String args[]) {
//定义为狗
Animal a = new Dog();
a.eat();
//a.lookDoor();报错,此时看父Animal,Animal中没有lookDoor()
System.out.println("---------");
//还原为狗
Dog d = (Dog) a;
d.eat();
d.lookDoor();
System.out.println("---------");
//变成猫
a = new Cat();
a.eat();
//a.playGame();报错,a还是Animal,没有playGame()
System.out.println("---------");
//还原成猫
Cat c = (Cat)a;
c.eat();
c.playGame();
System.out.println("---------");
}
}
运行结果:
狗吃肉
---------
狗吃肉
狗看门
---------
猫吃鱼
---------
猫吃鱼
猫玩捉迷藏
---------
多态的成员访问特点:
方法:编译看左边,运行看右边
继承的时候:
子类中有和父类中一样的方法,叫重写。
子类中没有父类中出现过的方法,方法就被继承过来了。
抽象类的概述:
动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。
我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。
没有{}的方法
如public abstract void eat();
java中抽象类中可以存在的抽象方法或接口中的方法不允许有方法体,但不属于方法体是空的。
抽象类的特点:
·抽象类和抽象方法必须用abstract关键字修饰。
·抽象类不一定有抽象方法,但是有抽象方法的类必须定义为抽象类。
·抽象类不能实例化。
因为它不是具体的。
抽象类有实例方法,但是不能实例化。构造方法的作用:用于子类访问父类数据的初始化
·抽象的子类
如果不想重写抽象方法,该类的子类是一个抽象类;
重写所有的抽象方法,这个时候子类是一个具体类。
抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
抽象类的成员特点:
成员变量:
既可以是变量,也可以是常量
构造方法:
有。用于子类访问父类数据的初始化
成员方法:
既可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
·抽象方法,强制要求子类做的事情
·非抽象方法,子类继承的事情,提高代码的复用性。
抽象类的几个问题:
·abstract不能和那些关键字共存?
private 冲突
final 冲突
static 无意义
接口的特点:
·用关键字interface表示
interface 接口名 {}
·类实现接口用implements表示
class 类名 implements接口名{}
·接口不能实例化
按照多态的方式去实例化
·接口的子类
可以是抽象类。但是意义不大
可以是具体类。要重写接口中的所有抽象方法。
由此可见
·具体类多态(几乎没有)
·抽象类多态(常用)
·接口多态(最常用)
接口成员特点:
成员变量:
只能是常量,并且是静态的。
默认修饰符:public static final
构造方法:
接口没有构造方法
成员方法:
只能是抽象方法
默认修饰符:public abstract
所有的类都默认继承自一个类,Object类
接口名+Impl这种格式是接口的实现类格式
如:InterImpl
类与类:
继承关系,只能单继承,可以多层继承
类与接口:
实现关系,可以单实现,也可以多实现,并且还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
抽象类和接口的区别:
·成员区别:
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量;只可以常量
成员方法:只可以抽象
·关系区别:
类与类:
继承,单继承
类与接口:
实现,单实现,多实现
接口与接口:
继承,单继承,多继承
·设计理念区别
抽象类被继承体现的是:"is a"的关系。抽象类中定义的是该继承体系的共性功能。
接口被实现体现的是:"like a"的关系。接口中定义的是该继承体系的扩展功能。
形式参数:
·基本类型
·引用类型:
类:
需要的是一个该类的对象,new 一个对象
如:new StudentDemo().method(new Student());
和下面的形式是一样的
StudentDemo sd = new StudentDemo();
Student s = new Student();
抽象类:
需要的是该抽象类的子类对象
接口:
需要的是该接口的实现类对象
返回值类型:
·基本类型
·引用类型:
类:
返回的是该类的对象
抽象类:
返回的是该抽象类的子类对象
接口:
返回的是该接口的实现类对象
包:
·其实就是文件夹
·作用:
把相同的类名放到不同的包中
对类进行分类管理
面试题:
package,import,class有没有顺序关系?
有。
package >import > class
package:只能有一个
import:可以有多个
class:可以有多个,以后建议是一个
权限修饰符:
本类 同一个包下(子类或无关类) 不同包下(子类) 不同包下(无关类)
public y y y y
protected y y y
默认 y y
private y
修饰符:
权限修饰符:private,默认,protected,public
状态修饰符:static,final
抽象修饰符:abstract
类:
权限修饰符:默认修饰符,public
状态修饰符:final
抽象修饰符:abstract
用的最多的就是:public
成员变量:
权限修饰符:private,默认,protected,public
状态修饰符:static,final
用的最多的就是:private
构造方法:
权限修饰符:private,默认,protected,public
用的最多的就是:public
成员方法:
权限修饰符:private,默认,protected,public
状态修饰符:final,static
抽象修饰符:abstract
用的最多的就是:public
除此以外的组合规则:
成员变量:public static final
成员方法:
public static
public abstract
public final
内部类概述:
把类定义在其他类的内部,这个类就被称为内部类
内部类的访问特点:
·内部类可以直接访问外部类的成员,包括私有
·外部类要访问内部类的成员,必须创建对象
如何直接访问内部类的成员:
外部类名。内部类名 对象名 = 外部类对象.内部类对象;
成员内部类的修饰符:
private 为了保证数据的安全性
static 为了方便访问数据
注意:静态内部类访问的外部类数据必须用静态修饰
成员内部类被静态修饰后的访问方式是:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
注意:
·内部类与外部类没有继承关系
·通过外部类名限定this对象
Outer.this
局部内部类:
·可以直接访问外部类的成员
·在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
面试题:
局部内部类访问局部变量的注意事项?
·必须用final修饰
匿名内部类:
就是内部类的简化写法。
前提:存在一个类或者接口
这里的类 可以是具体类也可以是抽象类。
格式:
new 类名或者接口名 () {
重写方法:
};
本质:
是一个继承了该类或者实现了该接口的子类匿名对象。