一个源文件*.java必须与该文件中的主类同名(public class),源文件中有且只有一个主类。-->主方法main-存在与主类中;一个源文件中可以存在N个普通类,直接使用。
类中常量:static、final同时修饰,此时常量全局唯一且不可修改,所有对象共享此常量
阿里编码规约:类中如无特殊说明,所有成员变量统一使用private 封装(99%)
属性 = 成员变量 = field = 域、字段
1.相同点:
1.1 定义变量的格式:数据类型 变量名 = 变量值
1.2 先声明,后使用
1.3 变量都有对应的作用域
2.不同点:
2.1 在类中声明的位置的不同
属性:直接定义在类的一对{}内
局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
2.2 关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:private、public 、缺省、protected ---->封装性
局部变量:不可以使用权限修饰符。
2.3默认初始化值的情况:
属性:类的属性,根据其类型,都默认初始化值。
整型 (byte、short、int 、long: 0)
浮点型 (float、double: 0.0)
字符型 (char: 0 (或'\u0000'))
布尔型 (boolean: false)
引用数据类型(类、数组、接口:null)
局部变量:没默认初始化值。
意味着,我们在调用局部变量之前,一定要显示赋值。
特别地,形参在调用时,我们赋值即可。
2.4 在内存中加载的位置:
属性:加载到堆空间中 (非static)
局部变量:加载到栈空间
3.属性赋值的先后顺序:
A.默认初始化 B.显示初始化 C.构造器中赋值 D.通过“对象.方法” 或 “对象.属性”的方式,赋值
以上操作的先后顺序:A -> B -> C -> D
1.成员变量:(类中的成员变量都在堆上保存)。
1.1 实例变量(不以static修饰):A.任何方法都可以调用,B.类加载过程中完成静态变量的内存分配,只分配一次内存,且在内存中只有一个备份,静态变量一改全改,C.通过类名可以直接调用静态变量
1.2 类变量(以static修饰):A.静态方法不能使用非静态的成员变量,只有实例化对象之后,才能调用;B.每创建一个实例,JVM就会为实例变量分配一次内存,可在内存中有多个拷贝,互不影响。
1.2 局部变量
1.2.1 形参(方法、构造器中定义的变量)1.2.2 方法局部变量(在方法内定义)
1.2.3 代码块局部变量(在代码块内定义)
注:局部变量的初始值必须被显式声明!(局部变量没有默认初始化值)
1.静态成员变量:类加载时创建,与类同命(静态属性保存在JVM的方法区)
2.成员变量:实例被创建时与实例对象同命
3.局部变量:在定义该变量的方法被调用时创建,与方法同命
方法 = 成员方法 = 函数 = method
方法:描述类应该具有的功能。
比如:Math类:sqrt()\random()\...
Scanner类:nextXxx() ...
Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ....
1.举例:
public void eat(){}
public void sleep(int hour){}
public String getName(){}
public String getNation(String nation){}
2.方法的声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
3.说明:
3.1 关于权限修饰符:默认方法的权限修饰符都先使用public
Java规定的4种权限修饰符:private、public 、缺省、protected---->封装性的体现
3.2 返回值类型: 返回值 vs 没返回值
3.2.1 如果方法返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要 使用return关键字来返回指定类型的变量或常量:“return 数据”。
如果方法没有返回值,则方法声明时,使用void来表示,通常,没返回值的方法中,使用return,但是,此时,只能:“return ;” 表示结束此方法的意思。
3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
3.4 形参列表:方法可以声明0个,1个,或多个形参。
3.4.1格式:数据类型1 形参1,数据类型2 形参2,...
3.5 方法体:方法功能的体现。
方法的使用中,可以调用当前类的属性或方法。
特殊的:方法A中又调用了方法A:递归方法。
方法中,不可以定义方法。
4.方法的形参的值传递机制:值传递
所谓的值传递,就是将实参值的副本传入方法里,而参数本身并不受影响。
形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据
值传递机制:
如果参数时基本数据类型,此时实参赋给形参的时是实参真实存储的数据值。
如果参数时引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
1.定义:在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可。
两同一不同”:同一个类、相同方法名
参数列表不同:参数个数不同,参数类型不同
2.举例:
Arrays类中重载的sort() / binarySearch()
3.判断是否重载:
跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
4.在通过对象调用方法时,如何确定某一个指定的方法 :
方法名------>参数列表
重载:不表现为多态性。
重写:表现为多态性。
1.从编译和运行的角度来看:
重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数列表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。他们的调用地址在编译期间就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。
所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法,这称为“早绑定”或“静态绑定”;
而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”;
引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”
1.非静态方法
非静态的方法就是没有static修饰的方法,对于非静态方法的调用,是通过对象来调用的
对象.方法()
public class InvokeMethod{
public static void main(String[] args){
InvokeMethod in = new InvokeMethod();
in.t1();
}
public void t1(){
}
}
2.静态方法
静态方法就是用static修饰的方法,静态的方法的调用是通过类名来调用的
类名.方法()
public class InvokeMethod{
public static void main(String[] args){
InvokeMethod.t2();
}
public static void t2(){
}
}
3.方法与方法之间的调用
3.1静态方法内部调用其他方法
如果在本类当中,静态方法可以直接调用静态方法,除了在main方法中,还可以在自定义的静态方法中直接调用。如果在本类当中是非静态方法,就必须通过对象来调用。
public class InvokeMethod{
public static void main(String[] args){
t2();
}
public static void t2(){
system.out.println("static t2...");
}
public static void t1(){
//静态方法调用非静态方法需通过对象来调用
//InvokeMethod in = new InvokeMethod();
//in.t2();
t2();
system.out.println("static t1");
}
}
如果在不同类当中,静态方法调用其他类的非静态方法,需要导入该类中的包,以及通过创建对象调用。
3.2非静态方法内部调用
如果在本类中,非静态方法可以直接调用静态方法与非静态方法。
在不同类中,非静态方法调用其他类的静态方法,需要通过导入该类中的包,并且需要通过类名来调用。
在不同类中,非静态方法调用其他类的非静态方法时,需要导入该类中的包,还需要通过创建对象来掉用。
注:构造器名必须与本类的public访问修饰符的类名相同。
1.构造器的作用:
1.1 创建对象 1.2 初始化对象的信息
构造方法是执行对象的初始化操作(初始化:类中成员变量赋值)
构造方法就是给类中属性赋值,类中属性的类型,在定义时就规定好了。
2.说明:
2.1 如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器
2.2 定义构造器的格式:权限修饰符 类名(形参列表){}
2.3 一个类中定义的多个构造器,彼此构成重载
2.4 一旦我们显示的定义了类的构造器之后,系统就不再提供默认的空参构造器
2.5 一个类中,至少会有一个构造器。
2.6 构造方法的互相调用:【使用this(相应参数),必须放在该方法的第一行调用,并且调用不能成"环",不能递归调用成环】
关于构造器的特殊点:(private修饰构造方法)A. 产生对象时,由JVM调用 B. 一旦构造方法被private修饰,这个类就不能通过外部产生对象;举例:对象个数有限,类内部提供方法产生对象,当一个类构造方法被private修饰,表示不希望它能通过外部产生对象,二由类本身向外提供对象,外部只能使用,不能创建。eg:星期类(周一 ~ 周天这七个对象)、地球类,只有一个对象。
public class Test1 {
public static void main(String[] args) {
Person person = Person.getInstance();
}
}
class Person{
private int age;
private String name;
private static Person per = new Person();
private Person(){
//类内部提供好对象,供外部使用
public static Person getInstance(){
return per;
}
}
}
1.代码块的作用:用来初始化类、对象
2.代码块如果有修饰的话,只能用static.
3.分类:静态代码块 vs 非静态代码块
3.1静态代码块
>内部可以有输出语句
>随着类的加载而执行,而且只执行一次
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要优于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
3.2非静态代码块
>内部可以有输出语句
>随着对象的创建而执行
>每创建一个对象,就执行一次非静态代码块
>作用:可以在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
对属性可以赋值的位置: (1)默认初始化 (2)显示初始化 (3)构造器中初始化 (4)有了对象以后,可以通过“对象.属性”或“对象.方法”的方式,进行赋值 (5)在代码块中赋值
执行的先后顺序:(1)->(2)/(5)->(3)->(4) 静态代码块 > 动态初始化块 > 构造器
A.普通代码块:定义在方法中的代码块【知道即可】
B.构造块:定义在类中,不加任何修饰符,直接使用{}定义的代码块
当产生对象时执行构造代码块,优先于构造方法执行。有几个对象产生,构造代码块就执行几次。
C.静态代码块:一般用于初始化静态成员属性。
定义在类中,使用static修饰的代码块。当类加载时执行一次,与对象产生无关。
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
静态代码块执行完毕后,构造代码块(执行),在然后是构造方法执行。
D.同步代码块:(多线程)
class Person {
String name;
int age;
static String desc = "我是一个人";
public Person() {
}
public Person(String name, int age) {
this.age = age;
this.name = name;
}
// static代码块
static {
System.out.println("hello,static Block->1");
System.out.println("我是一个爱学习的人");
}
static {
System.out.println("hello,static Block->2");
// 调用静态结构
desc = "我是一个爱学习的人";
// 不可以调用非静态结构
// name = "Tom";
}
// 非static代码块
{
System.out.println("hello,Block->1");
System.out.println("hello,Block->2");
// 调用非静态结构
age = 1;
// 调用静态结构
desc = "我是一个爱学习的人1";
}
}
阿里笔试题:
public class D extends B{
public D(){
System.out.println("4.D的构造方法");
}
{
System.out.println("5.D的构造块");
}
static{
System.out.println("6.D的静态代码块");
}
/**
* 此时主方法所在的类D有静态代码块
* 在执行主方法之前先加载类(先执行静态代码块)
* -> 先加载B而后加载D
* new D() -> 产生子类对象
* 先调用父类的构造方法产生父类对象
* @param args
*/
public static void main(String[] args) {
System.out.println("7.............");
new D();
new D();
System.out.println("8.............");
/*
执行结果:3.B的静态块
6.D的静态代码块
7.............
2.B的构造块
1.B的无参构造
5.D的构造块
4.D的构造方法
2.B的构造块
1.B的无参构造
5.D的构造块
4.D的构造方法
8.............
*/
}
}
class B{
public B(){
System.out.println("1.B的无参构造");
}
{
System.out.println("2.B的构造块");
}
static{
System.out.println("3.B的静态块");
}
}
成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
成员内部类必须依赖于外部类的存在而存在,必须先有外部类对象才能产生成员内部类。
//成员内部类对象的产生
Inner in = new Inner();
//外部类的外部:前提是内部类对于外部的这个类可见的
Outter.Inner in = new Outter().new Inner();
//new Outter():产生了外部类的对象,然后通过此对象来构造内部类对象 => 当产生内部类对象时,构造这个内部类的外部类对象就会被编译器传入内部类
成员内部类实际上JVM会传入一个隐藏的外部类对象Outter.this
Outter.Inner1 inner = new Outter().new Inner();
//外部类Outter的对象在产生内部类的时候就由JVM传递给内部类
System.out.println(Outter.this.age);
内部类和外部类可以方便的访问彼此的私有域
无论那种内部类,在外部类的内部使用内部类的成员方法和成员属性,都必须显式的通过内部类对象来访问。反之,对于成员内部类来说,成员内部类先有外部类对象后才能创建成员内部类对象。
Outter.Inner in = new Outter().newInner();
内部类访问外部类的私有域直接访问
外部类要访问内部类的私有域,必须通过对象来访问。
class Outter{
private String msg = "outter类中的msg属性";
//心脏和发动机都属于私有内部类,对外部完全隐藏,只是在类的内部来使用
class Inner{
private int num = 10;
private String msg = "内部类的msg属性";
public void test(){
//直接访问外部类的msg属性
//此处直接访问了外部类的私有成员变量msg,成员变量必须通过对象访问
System.out.println(Outter.this.msg);
//Outter.this.msg:内部类中隐藏了一个外部类的对象
}
}
}
成员内部类不能定义静态变量,成员内部类必须要依赖于外部类,若成员内部类有静态属性,没有外部类对象也能访问了
对于外部类来说,能否在外部类的静态方法中使用成员内部类? => 相当于在静态方法中调用成员变量 不行!比如:在外部类的main中创建内部类对象
成员内部类,一方面,作为外部类的成员:
>调用外部类的结构
>可以被static修饰
>可以被4种不同的权限修饰
另一方面,作为一个类:
>类内可以定义属性、方法、构造器等。
>可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
>可以被abstract修饰
小点:成员内部类和局部内部类,在编译之后,都会生成字节码文件。
格式:成员内部类:外部类$内部类名:class
局部内部类:外部类$数字 内部类名.class
// 开发中很少见
public void method() {
// 局部内部类
class AA {
}
}
在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量
(比如:num)的话,要求此局部变量声明为final的。
jdk 7及之前的版本,要求此局部变量显示的声明为final的
jdk 8及之后的版本,可以省略final的声明
public void method() {
//局部变量
int num = 10;
class AA {
public void show() {
// num = 20;//不可被修改
}
}
}
这个自我感觉还是一个特殊的点:静态内部类可以有自己的成员变量。
使用匿名内部类有个前提条件:必须继承一个父类或实现一个接口,普通类和抽象类都可以,但最多只能继承一个父类,或实现一个接口
关于匿名内部类必须要知道的两点知识:
1、匿名内部类不能有构造器(构造方法),匿名内部类没有类名,不能定义构造器,构造方法的方法名是要与类名一致,但匿名内部类可以定义实例初始化块。
2、匿名内部类不可以是抽象类,匿名内部类不能有构造器,而抽象类可以有构造方法,java在创建匿名内部类的时候,会立即创建内部类的对象,而抽象类不能创建实例,
interface Father{
public abstract void speak();
}
public class NIMingDemo {
public static void main(String[] args) {
Father f=new Father() {
@Override
public void speak() {
System.out.println("粑粑:孩子,不你不想拉粑粑");
}
public void eatBaBa(){
System.out.println("熊孩子:粑粑,我想拉粑粑");
}
};
f.speak();
f.eatBaBa(); //编译失败,不能调用eatBaBa()方法
}
}
程序过程中, f.eatBaBa(); 会编译失败,提示不能调用eatBaBa()方法,因为 Father f=new Father()创建的是Father的对象,而非匿名内部类的对象。其实匿名内部类连名字都没有,咋实例对象去调用它的方法呢?但是f.speak()方法却可以执行,因为匿名内部类实现了接口Father的
speak()方法,因此可以借助Father的对象去调用。
如果想调用匿名内部类的自定义的eatBaBa()方法,有两个方法:
方法一、 事实上匿名内部类中隐含一个匿名对象,通过该方法可以直接调用eatBaBa()和speak()方法;具体代码如下:
interface Father{
public abstract void speak();
}
public class NIMingDemo {
public static void main(String[] args) {
new Father() {
@Override
public void speak() {
System.out.println("粑粑:孩子,不你不想拉粑粑");
}
public void eatBaBa(){
System.out.println("熊孩子:粑粑,我想拉粑粑");
}
}.eatBaBa() ;
}
}
只不过这个匿名对象只能使用一次!
方法二、 把eatBaBa()方法更改为speak()方法一样的使用,也就是说在Father接口中声明eatBaBa()方法,然后在匿名内部类中覆写此方法即可。这个就不贴代码了!
匿名内部类在多线程上的实现
匿名内部类最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
public class ThreadDemo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.print(i);
}
}
};
t.start();
}
}
//运行结果: 123
public class InnerClass_Test {
public static void main(String[] args) {
// 4.1实例化成员内部类的对象---------------------------------------
// 创建Dog实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
dog.show();
// 创建Bird实例(非静态的成员内部类):
// Person.Bird brid = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
System.out.println();
bird.display("黄鹂");
}
}
class Person {
String name = "小明";
int age;
public void eat() {
}
// 静态成员内部类
static class Dog {
String name;
int age;
public void show() {
}
}
// 非静态成员内部类
class Bird {
String name = "杜鹃";
public Bird() {
}
public void sing() {
Person.this.eat();// 调用外部类的非静态属性
}
// 4.2 在成员内部类中区分调用外部类的结构
public void display(String name) {
System.out.println(name);// 方法的形参// :黄鹂
System.out.println(this.name);// 内部类的属性// :杜鹃
System.out.println(Person.this.name);// 外部类的属性// :小明
}
}
}
public class InnerClassTest1 {
// 返回一个实现了Comparable接口的类的对象
public Comparable getComparable() {
// 创建一个实现了Comparable接口类:局部内部类
// 方式一:
class MyComparable implements Comparable{
@Override
public int compareTo(Object o) {
return 0;
}
}
// return new MyComparable();
// 方式二:(匿名的方式:匿名内部类的匿名对象)
return new Comparable() {
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
};
}
}
这篇博客非常好!!!!!
JavaSE基础知识(二十)--Java内部类之为什么需要内部类_ruidianbaihuo的博客-CSDN博客