文章目录
前言
代码练习
详细的解释都在代码中给出
成员变量和局部变量的区别?
package 面向对象;
/*
成员变量和局部变量的区别?
A:在类中的位置不同
成员变量:在类中方法外
局部变量:在方法定义中或者方法声明上
B:在内存中的位置不同
成员变量:在堆内存
局部变量:在栈内存
C:生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
D:初始化值不同
成员变量:有默认初始化值
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。
注意事项:
局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
*/
class Varialbe {
//成员变量
//int num = 10;
int num; //0
public void show() {
//int num2 = 20; //局部变量
//可能尚未初始化变量num2
//int num2; //没有默认值
int num2 = 20;
System.out.println(num2);//这里报错,num2没有默认值
int num = 100;
System.out.println(num);
}
}
class VariableDemo {
public static void main(String[] args) {
Varialbe v = new Varialbe();
System.out.println(v.num); //访问成员变量 0
v.show();// 20 100
}
}
匿名对象
package 面向对象;
/*
匿名对象:就是没有名字的对象。
匿名对象的应用场景:
A:调用方法,仅仅只调用一次的时候。
注意:调用多次的时候,不适合。因为会重新生成对象
那么,这种匿名调用有什么好处吗?
有,匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。
B:匿名对象可以作为实际参数传递
*/
class NiMing {
public void show() {
System.out.println("我爱学习");
}
}
class NiMingDemo {
public void method(NiMing s) {
s.show();
}
}
class NoNameDemo {
public static void main(String[] args) {
//带名字的调用
NiMing s = new NiMing();
s.show();
s.show();
System.out.println("--------------");
//匿名对象
//new NiMing();
//匿名对象调用方法
new NiMing().show();
new NiMing().show(); //这里其实是重新创建了一个新的对象
System.out.println("--------------");
//匿名对象作为实际参数传递
NiMingDemo sd = new NiMingDemo();
//NiMing ss = new NiMing();
//sd.method(ss); //这里的s是一个实际参数
//匿名对象
sd.method(new NiMing());
//在来一个
new NiMingDemo().method(new NiMing());
}
}
内部类
- 匿名内部类
- 成员内部类
- 局部内部类
package 面向对象;
/**
* 匿名内部类
* 就是内部类的简化写法。
*
* 前提:存在一个类或者接口
* 这里的类可以是具体类也可以是抽象类。
*
* 格式:
* new 类名或者接口名(){
* 重写方法;
* }
*
* 本质是什么呢?
* 是一个继承了该类或者实现了该接口的子类的匿名对象。
*/
interface Inter4 {
public abstract void show();
public abstract void show2();
}
/**
内部类概述:
把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。
内部的访问特点:
A:内部类可以直接访问外部类的成员,包括私有。
B:外部类要访问内部类的成员,必须创建对象。
*/
class Outer1 {
private int num = 10;
class Inner1 {
public void show() {
//内部类可以直接访问外部类的成员,包括私有。
System.out.println(num);
}
}
public void method() {
//找不到符号
//show();
//外部类要访问内部类的成员,必须创建对象。
Inner1 i = new Inner1();
i.show();
}
/**
* 成员内部类的修饰符:
* private 为了保证数据的安全性
* static 为了方便访问数据
* 注意:静态内部类访问的外部类数据必须用静态修饰。
*/
private static int num2 = 100;
public static class Inner2{
public void show(){
//System.out.println(num);
System.out.println(num2);
}
public static void show2() {
//System.out.println(num);//报错。静态内部类访问的外部类数据必须用静态修饰。
System.out.println(num2);
}
}
/**
* 注意:
* 1:内部类和外部类没有继承关系。
* 2:通过外部类名限定this对象
* Outer.this
*/
public int num3 = 10;
class Inner3{
public int num3 = 20;
public void show(){
int num3 = 30;
System.out.println(num3);//30
System.out.println(this.num3);//20
System.out.println(Outer1.this.num3);//10
System.out.println(num);//10
}
}
/**
* 局部内部类
* A:可以直接访问外部类的成员
* B:在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
*
* 注意事项:
* 局部内部类访问局部变量的注意事项?
* A:局部内部类访问局部变量必须用final修饰
* B:为什么呢?
* 局部变量是随着方法的调用而调用,随着调用完毕而消失。
* 而堆内存Inner的内容并不会立即消失。所以,我们加final修饰。
* 加入final修饰后,这个变量就成了常量。既然是常量。你消失了。
* 我在内存中存储的是数据20,所以,我还是有数据在使用。
*/
private int num4 = 40;
public void method2(){
final int num5 = 50;//局部内部类访问局部变量必须用final修饰
class Inner{
public void show(){
System.out.println(num4);
System.out.println(num5);
}
}
Inner i = new Inner();
i.show();
}
public void method3() {
Inter4 i = new Inter4() { //多态
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();//是一个继承了该类或者实现了该接口的子类的匿名对象。所以可以调用方法
i.show2();
}
}
class InnerClassDemo {
public static void main(String[] args) {
//需求:我要访问Inner类的show()方法
//格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer1.Inner1 oi1 = new Outer1().new Inner1();
oi1.show();//10
System.out.println("--------------------------");
//成员内部类被静态修饰后的访问方式是:
//格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
Outer1.Inner2 oi2 = new Outer1.Inner2();
oi2.show();
oi2.show2();
//show2()的另一种调用方式。因为静态方法,可以通过类名调用。
Outer1.Inner2.show2();
System.out.println("--------------------------");
Outer1.Inner3 oi3 = new Outer1().new Inner3();
oi3.show();
System.out.println("--------------------------");
Outer1 o = new Outer1();
o.method2();
System.out.println("--------------------------");
Outer1 o2 = new Outer1();
o.method3();
}
}
基本类型与引用类型
package 面向对象;
/*
形式参数的问题:
基本类型:形式参数的改变不影响实际参数
引用类型:形式参数的改变直接影响实际参数
*/
//形式参数是基本类型
class Demo_ji {
public int sum(int a,int b) {
a=b;
b=a+b;
System.out.println("a:"+a+",b:"+b);
return a + b;
}
}
//形式参数是引用类型
class Demo_yin {
public void show() {
System.out.println("我爱学习");
}
public void reverse(int[] arr){
int t;
for (int i = 0; i < (arr.length/2); i++) {
t=arr[i];
arr[i]=arr[arr.length - i -1];
arr[arr.length - i -1]=t;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
}
}
class Demo {
//如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
public void method(Demo_yin s) { //调用的时候,把main方法中的s的地址传递到了这里 Student s = new Student();
s.show();
}
}
class ArgsTest {
public static void main(String[] args) {
//形式参数是基本类型的调用
//基本类型:形式参数的改变对实际参数没有影响。基本类型传递的是数据值
Demo_ji d = new Demo_ji();
int a=10;int b=20;
int result = d.sum(a,b);
System.out.println("result:"+result);//a:20,b:40 result:60
System.out.println("a:"+a+",b:"+b);//a:10,b:20
System.out.println("--------------");
//形式参数是引用类型的调用
//需求:我要调用Demo类中的method()方法
Demo sd = new Demo();
//创建引用对象
Demo_yin s = new Demo_yin();
sd.method(s); //把s的地址给到了这里
System.out.println("--------------");
//引用类型:形式参数的改变直接影响实际参数。引用类型传递的是地址值
int[] arr = {1,2,3,4,5};
s.reverse(arr);//54321
System.out.println("--------------");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);//54321
}
}
}
标准类
- 封装
- static
- this
- hashcode
- tostring
- equals 与 ==
- 静态代码块,构造代码块,构造方法的执行顺序?
- 代码:Student s = new Student();做了哪些事情?
package 面向对象;
public class Student {
/**
* private:私有的。可以修饰成员变量和成员方法。
* 注意:被private修饰的成员只能在本类中访问。
* 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
*/
//姓名
private String name;
//年龄
private int age;
/**
* 针对多个对象有共同的这样的成员变量值的时候,
* Java就提高了一个关键字来修饰:static。
* static关键字注意事项
* A:在静态方法中是没有this关键字的
* 如何理解呢?
* 静态是随着类的加载而加载,this是随着对象的创建而存在。
* 静态比对象先存在。先存在的,不能访问后面进来的。
* B:静态方法只能访问静态的成员变量和静态的成员方法
* 静态方法:
* 成员变量:只能访问静态变量
* 成员方法:只能访问静态成员方法
* 非静态方法:
* 成员变量:可以是静态的,也可以是非静态的
* 成员方法:可是是静态的成员方法,也可以是非静态的成员方法。
* 简单记:
* 静态只能访问静态。
*/
static String country;
//非静态变量
int num = 10;
//静态变量
static int num2 = 20;
//构造方法
//public Student() {
//}
/**
* 代码块:在Java中,使用{}括起来的代码被称为代码块。
* 根据其位置和声明的不同,可以分为
* 局部代码块:局部位置,用于限定变量的生命周期。
* 构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行构造代码块。
* 作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化。
* 静态代码块:在类中的成员位置,用{}括起来的代码,只不过它用static修饰了。
* 作用:一般是对类进行初始化。
*
* 面试题?
* 静态代码块,构造代码块,构造方法的执行顺序?
* 静态代码块 -- 构造代码块 -- 构造方法
* 静态代码块:只执行一次
* 构造代码块:每次调用构造方法都执行
*/
static {
System.out.println("Student 静态代码块");
}
public Student() {
System.out.println("Student 构造方法");
}
{
System.out.println("Student 构造代码块");
}
/**
* this
* (1)代表当前类的引用对象
* 记住:哪个对象调用方法,该方法内部的this就代表那个对象
* (2)this的应用场景:
* A:解决了局部变量隐藏成员变量的问题
*
* 构造方法:
* 给对象的数据进行初始化
*
* 格式:
* A:方法名与类名相同
* B:没有返回值类型,连void都没有
* C:没有具体的返回值
*/
//构造方法
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public Student(String name,int age,String country) {
this.name = name;
this.age = age;
this.country = country;
}
public static String getCountry() {
return country;
}
public static void setCountry(String country) {
Student.country = country;
}
//带返回值的成员方法
public String getName() {
//this:哪个对象调用那个方法,this就代表那个对象
return name;
}
//不带返回值的成员
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
//带参数的成员方法
public void setAge(int age) {
this.age = age;
}
//输出所有的成员变量值
public void show() {
System.out.println("姓名:"+name+",年龄:"+age+",国籍:"+country);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", num=" + num +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package 面向对象;
public class StudentTest {
/**
* public:权限最大
* static:不用创建对象调用
* void:返回值给jvm没有意义
* main:就是一个常见的名称。
* String[] args:可以接收数据,提供程序的灵活性
* 格式:java MainDemo hello world java
* java MainDemo 10 20 30
* @param args
*/
static {
System.out.println("主函数中静态代码块");
}
public static void main(String[] args) throws CloneNotSupportedException {
/** 代码:Student s = new Student();做了哪些事情?
* (1)把Student.class文件加载到内存
* (2)在栈内存为s开辟空间
* (3)在堆内存为学生对象申请空间
* (4)给学生的成员变量进行默认初始化。null,0
* (5)给学生的成员变量进行显示初始化。林青霞,27
* (6)通过构造方法给成员变量进行初始化。刘意,30
* (7)对象构造完毕,把地址赋值给s变量
*/
//方式1给成员变量赋值
//无参构造+setXxx()
Student s1 = new Student();
s1.setName("林青霞");
s1.setAge(27);
//输出值
System.out.println(s1.getName()+"---"+s1.getAge());
s1.show();
//方式2给成员变量赋值
Student s2 = new Student("刘意",30);
System.out.println(s2.getName()+"---"+s2.getAge());
s2.show();
Student s3 = new Student("邓丽君",16,"中国");
s3.show();
Student s4 = new Student();
System.out.println(s4.num);//10
System.out.println(Student.num2);//推荐类名调用
System.out.println(s4.num2);//20
Student s5 = new Student();
/*
* 主函数中静态代码块
Student 静态代码块
Student 构造代码块
Student 构造方法
林青霞---27
姓名:林青霞,年龄:27,国籍:null
Student 构造代码块
刘意---30
姓名:刘意,年龄:30,国籍:null
Student 构造代码块
姓名:邓丽君,年龄:16,国籍:中国
Student 构造代码块
Student 构造方法
10
20
20
Student 构造代码块
Student 构造方法
* */
System.out.println("----------------------------");
Student s6 = new Student();
/*
Student 构造代码块
Student 构造方法
*/
/**
* Object:类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
* 每个类都直接或者间接的继承自Object类。
*
* Object类的方法:
* public int hashCode():返回该对象的哈希码值。
* 注意:哈希值是根据哈希算法计算出来的一个值,这个值和地址值有关,但是不是实际地址值。
* 你可以理解为地址值。
*
* public final Class getClass():返回此 Object 的运行时类
* Class类的方法:
* public String getName():以 String 的形式返回此 Class 对象所表示的实体
*/
System.out.println("----------------------------");
Student o1 = new Student();
System.out.println(o1.hashCode());//1163157884
Student o2 = new Student();
System.out.println(o2.hashCode());//1956725890
Student o3 = o1;
System.out.println(o3.hashCode());//1163157884
System.out.println("------------------------------");
Student o4 = new Student();
Class c = o4.getClass();
System.out.println(c);//class 面向对象.Student
String str = c.getName();
System.out.println(str); // 面向对象.Student
//链式编程
String str2 = o4.getClass().getName();
System.out.println(str2);//面向对象.Student
System.out.println("-----------------------------");
/**
* public String toString():返回该对象的字符串表示。
* 直接输出一个对象的名称,其实就是调用该对象的toString()方法。
*
* Integer类下的一个静态方法:
* public static String toHexString(int i):把一个整数转成一个十六进制表示的字符串
*
* toString()方法的值等价于
* getClass().getName() + '@' + Integer.toHexString(hashCode())
* this.getClass().getName()+'@'+Integer.toHexString(this.hashCode())
*/
System.out.println(o4.toString());// 面向对象.Student@1540e19d
System.out.println(o4.getClass().getName() + '@'
+ Integer.toHexString(o4.hashCode()));//面向对象.Student@1540e19d
System.out.println(o4);//面向对象.Student@1540e19d
System.out.println("--------------------");
/**
* public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。
* 这个方法,默认情况下比较的是地址值。比较地址值一般来说意义不大,所以我们要重写该方法。
* 怎么重写呢?
* 一般都是用来比较对象的成员变量值是否相同。
* 重写的代码优化:提高效率,提高程序的健壮性。
* 最终版:
* 其实还是自动生成。
*
* 看源码:
* public boolean equals(Object obj) {
* //this - s1
* //obj - s2
* return (this == obj);
* }
*
* ==:
* 基本类型:比较的就是值是否相同
* 引用类型:比较的就是地址值是否相同
* equals:
* 引用类型:默认情况下,比较的是地址值。
* 不过,我们可以根据情况自己重写该方法。一般重写都是自动生成,比较对象的成员变量值是否相同
*/
Student e1 = new Student("e1",1);
Student e2 = new Student("e1",1);
System.out.println(e1==e2);//false
Student e3 = e1;
System.out.println(e1==e3);//true
System.out.println(e1.equals(e2));//false
System.out.println(e1.equals(e1));//true
System.out.println(e1.equals(e3));//true
System.out.println("--------------------");
/**
* protected void finalize():当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。用于垃圾回收,但是什么时候回收不确定。
* protected Object clone():创建并返回此对象的一个副本。
* A:重写该方法
*
* Cloneable:此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
* 这个接口是标记接口,告诉我们实现该接口的类就可以实现对象的复制了。
* 让被克隆的类实现该接口,才可以克隆
*/
// Student c1 = new Student();
// c1.setName("克隆");
// c1.setAge(22);
克隆
// Object obj = c1.clone();
// Student c2= (Student) obj;
}
}