目录
局部变量和成员变量的区别
- 在类中的位置不同:成员变量在类方法外,局部变量在方法定义中或者方法声明上;
- 在内存的位置不同:成员变量在堆内存中,局部变量在栈内存中;
- 生命周期不同:成员变量随着对象的创建而存在,随着对象的消失而消失,局部变量随着方法的调用而存在,随着方法的调用完毕而消失;
- 成员变量有默认的初始化值,局部变量没有初始化值,必须定义赋值然后才可以使用;
- 注意事项:局部变量名称可以和成员变量一样,在方法中使用的时候,采用的是就近原则;基本的数据类型变量包括:byte,short,int,long,float,double,boolean,char,引用数据类型包括:数组、类、接口、枚举。
匿名对象
匿名对象就是指的是没有名字的对象。匿名对象适合于仅仅调用一次的时候,这样可以节省代码,但是因为这种定义方式调用完毕就是垃圾,会被垃圾回收器回收,所以不适合调用多次的时候。
package java_ws.e;
public class Demo1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car c = new Car();
c.run();
//定义一个匿名对象
new Car().run();
//匿名对象也可以对属性进行修改,但是只会执行一次,然后就会被垃圾回收
new Car().name = 100;
System.out.println(c.name);
}
}
//定义一个类
class Car {
private String color;
int name;
public void run() {
System.out.println("车跑起来");
}
}
private关键字的概述和特点
private关键字特点:
- 是一个权限修饰符
- 可以修饰成员变量和成员方法
- 被其修饰的成员只能在本类中使用,其他类如果需要访问这个私有属性或者私有方法那么需要通过get或者set方法进行访问
- private只能说是封装的一种体现形式,不能说封装就是私有
static关键字
static关键字的特点:
- 随着类的加载而加载
- 优先于对象存在
- 被类的所有对象共享(比如说大家公用的东西)
- 静态本身可以通过对象进行调用,但是一般更推荐使用类名进行调用
static的注意事项:
- 在静态方法中是没有this关键字的,静态是随着类的加载而加载的,this是随着对象的创建而存在的,也就是说静态比对象先存在
- 静态方法只能访问静态的成员变量和静态的成员方法
静态变量和成员变量的区别:
- 静态变量属于类,成员变量属于对象
- 静态变量存储于方法区的静态区,成员变量存储于堆内存
- 静态变量随着类的加载而加载,随着类的消失而消失;成员变量随着对象的创建而存在,随着对象的消失而消失
- 静态变量可以通过类名进行调用,也可以通过对象进行调用,成员变量只能通过对象进行调用(或者this)
构造方法与set、get方法比较
一般来说,成员变量的赋值操作有两种方式,一种是构造方法,一种是通过set或者get方法。那么这二者有什么区别呢?
构造方法严格来说是对成员变量进行初始化,而一旦初始化的话成员变量的值是不能通过构造方法直接进行修改的(在不改变对象的内存地址的前提下)还是需要get或者set方法进行修改。而get或者set方法可以对成员变量进行初始化,也可以直接进行修改值,所以在以后的开发中可能用getset方法进行成员变量初始化的情况要多一些。
代码块概述
代码块概述,在Java中,使用{}括起来的代码被称为代码块。根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
常见代码块的应用
局部代码块:在方法中出现;限定变量生命周期,及早释放,提高内存利用率
构造代码块 (初始化块):在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造 方法前执行(主要面试用,开发基本不用)
静态代码块:在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。一般用于加载驱动
package java_ws.e;
class Student {
static {
System.out.println("Student 静态代码块");
}
//构造代码块优先于构造方法的执行
{
System.out.println("Student 构造代码块");
}
public Student() {
System.out.println("Student 构造方法");
}
}
class Demo4 {
//静态代码块是优先于主方法执行的
static {
System.out.println("Demo2_Student静态代码块");
}
public static void main(String[] args) {
System.out.println("我是main方法");
Student s1 = new Student();
Student s2 = new Student();
}
}
/*
* Demo2_Student静态代码块
我是main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
Student 构造代码块
Student 构造方法
*/
继承
继承的好处:
- 提高了代码的复用性
- 提高了代码的维护性
- 让类和类之间产生关系,是多态的前提
继承的弊端:
- 类的耦合性增强了
- 开发的原则,高内聚,低耦合
Java中继承的特点:Java中只支持单继承,不支持多继承(一个儿子只能有一个爹);Java支持多层继承。
继承中的注意事项:
- 子类只能继承父类所有非私有的成员(成员方法或者成员变量)
- 子类不能继承父类的构造方法,但是可以通过super关键字去访问
- 使用继承的时候还要应该判断这两个类实际之间的关系,比如:项目经理:姓名、工号、性别、奖金;程序员:姓名、工号、性别;但是我们不能让项目经理去继承程序员,而应该是向上抽取出一个父类员工类。
this和super的区别
this代表当前对象的引用,谁调用我我就代表谁;super代表当前对象父类的引用。
this和super的区别:
- this.成员变量 调用本类的成员变量,也可以调用父类的成员变量;super.成员变量 调用父类的成员变量
- this(...) 调用本类的构造方法;super(...) 调用父类的构造方法
- this.成员方法 调用本类的成员方法,也可以调用父类的方法;super.成员方法 调用父类的成员方法
- this和super调用构造方法的时候必须出现在构造方法的第一条语句上
package java_ws.e;
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");
}
}
class Demo4 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
重写和重载
重写(override):子类出现和父类的方法声明一模一样的方法,与返回值类型有关返回值是一致的(或者是子父类的)
重载(overload):本类中出现的方法名一样,参数列表不同的方法,与返回值类型无关
* B:final修饰特点
* 修饰类,类不能被继承
* 修饰变量,变量就变成了常量,只能被赋值一次
* 修饰方法,方法不能被重写
包
之所以要出现包是因为在进行项目开发的时候我们可能会定义成百上千个模块,如果把这些模块都放在一起那么会看起来非常乱,而且用起来也不方便。
包名要写在整个代码的第一行,而且一个模块中只能有一个包名。
举例:
学生:增加,删除,修改,查询
老师:增加,删除,修改,查询
方案1:按照功能分
com.heima.add
AddStudent
AddTeacher
com.heima.delete
DeleteStudent
DeleteTeacher
com.heima.update
UpdateStudent
UpdateTeacher
com.heima.find
FindStudent
FindTeacher
方案2:按照模块分
com.heima.teacher
AddTeacher
DeleteTeacher
UpdateTeacher
FindTeacher
com.heima.student
AddStudent
DeleteStudent
UpdateStudent
FindStudent
修饰符
同一个包下(子类和无关类) | 不同包下(子类) | 本类 | 不同包下(无关类) | |
private | Y | |||
默认 | Y | Y | ||
protected | Y | Y | Y | |
public | Y | Y | Y | Y |
常见的修饰符:
* A:修饰符:
* 权限修饰符:private,默认的,protected,public
* 状态修饰符:static,final
* 抽象修饰符:abstract
* B:类:
* 权限修饰符:默认修饰符,public
* 状态修饰符:final
* 抽象修饰符:abstract
* 用的最多的就是:public
* C:成员变量:
* 权限修饰符:private,默认的,protected,public
* 状态修饰符:static,final
* 用的最多的就是:private
* D:构造方法:
* 权限修饰符:private,默认的,protected,public
* 用的最多的就是:public
* E:成员方法:
* 权限修饰符:private,默认的,protected,public
* 状态修饰符:static,final
* 抽象修饰符:abstract
* 用的最多的就是:public
* F:除此以外的组合规则:
* 成员变量:public static final
* 成员方法:
* public static
* public abstract
* public final
内部类
内部类访问特点:
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
- 创建内部类对象格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
- 如果内部类被private修饰,其他类无法通过上面的那么只能通过在外部类中创建内部类的实例对象进行访问
- 如果内部类被static修饰,创建内部类格式是:外部类名.内部类名 对象名 = 外部类名.内部类对象,因为静态变量可以直接通过类名进行调用
package java_ws.e;
public class Demo5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer.Inner oi = new Outer().new Inner();
oi.method();
}
}
class Outer {
class Inner {
public void method() {
System.out.println("Hello World");
}
}
}
局部内部类访问局部变量的问题
局部内部类在访问他所在方法中的局部变量必须用final修饰,为什么?
因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用
package java_ws.e;
public class Demo6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer1 oute = new Outer1();
oute.method();
}
}
class Outer1 {
public void method() {
//这里如果不是定义为final类型救护报错
final int num = 10;
class Inner1 {
public void print() {
System.out.println(num);
}
}
Inner1 i = new Inner1();
i.print();
}
}
匿名对象类
匿名内部类就是内部类的简化写法,前提是存在一个类或者接口,这里的类可以是具体类或者是抽象类。本质上是一个继承了该类或者实现了该接口的子类匿名对象。
格式:
new 类名或者接口名() {
重写方法;
}
package java_ws.e;
import java.lang.reflect.Method;
import org.omg.CORBA.PUBLIC_MEMBER;
public class Demo7 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer2 iOuter = new Outer2();
iOuter.method();
}
}
interface inter {
public void print();
}
class Outer2 {
class Inner2 implements inter {
public void print() {
System.out.println("jhjj");
}
}
public void method() {
new inter() {
@Override
public void print() {
// TODO Auto-generated method stub
System.out.println("hello");
}
}.print();
}
}
API概述
API是Java提供给我们使用的类,这些类将底层的实现封装了起来,我们是不需要关心这些类是如何实现的,我们只需要学习这些类时如何使用的。
Objec类
object类是类层次结构的根类,所有的类都直接或者间接的继承自该类。object中只有一个无参的构造方法。
object类中的方法
hashCode函数
package java_ws.e;
public class Demo8 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car s1 = new Car();
Car s2 = new Car();
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
返回值是哈希码值,默认情况下,该方法会根据对象的地址来进行计算。不同对象的hashCode值一般来说不会一样,但是同一对象的hashCode值肯定相同。
getClass方法
public final int getClass();
返回此object类的运行时类,可以通过class类中的一个方法,获取对象的真实类的全名称,比如public String getName();
package java_ws.e;
public class Demo8 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car s1 = new Car();
Car s2 = new Car();
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Class clazz = s1.getClass();
System.out.println(clazz.getName());
}
}
//输出的是Car类所在的包和相应的地址
equals函数
源码中表示的是两个对象的地址值是否相等,由于比较对象的引用没什么实际意义,可以直接用==来实现,所以一般建议重写该方法。因为在开发中我们一般比较的是属性值,我们认为相同属性是一个对象。
package java_ws.e;
public class Demo8 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Car s1 = new Car();
Car s2 = new Car();
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Class clazz = s1.getClass();
System.out.println(clazz.getName());
System.out.println(s1.equals(s2));
}
@Override
public String toString() {
return "Demo8 [toString()=" + super.toString() + "]";
}
}
@Override
//重写父类的方法函数名和参数列表必须一致,而且如果是返回值是基本类型那么重写的方法必须和覆盖的方法一致,
//如果是引用类型,那么重写方法的返回值类型可以相同,也可以是派生自被重写方法的返回类型
public boolean equals(Object obj) {
/*if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;*/
Car other = (Car) obj;
if (name != other.name)
return false;
return true;
}
注释:==是一个比较运算符号,既可以比较基本数据类型,也可以比较引用数据类型,基本数据类型比较的是值,引用数据类型比较的是地址值。
equals方法是一个方法,只能比较引用数据类型,所有的对象都会继承Object类中的方法,如果没有重写Object类中的equals方法,equals方法和==号比较引用数据类型无区别,重写后的equals方法比较的是对象中的属性。