//1.提供 get set 方法
class Person{
private int age;
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
/* @Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}*/
}
public class ObjectInit {
public static void main(String[] args) {
Person person = new Person();
person.setAge(18);
person.setName("qzz");
person.setSex("man");
// System.out.println(person);没有生成toString打印的是地址
System.out.println(person.getAge());
System.out.println(person.getName());
System.out.println(person.getSex());
}
}
2.1(对象的创建要分为哪几部)
a.为对象创个内存
b.调用合适的构造函数
带有参数的构造函数
this 指向的是当前对象的内存
//2.通过合适的构造函数进行初始化
// (系统本身会自动生成无参数的构造函数)
/* 2.1(对象的创建要分为哪几部)
a.为对象创个内存
b.调用合适的构造函数*/
//定义类Person1 自己不添加任何无参或有参数构造方法
class Person1{
private int age;
private String name;
private String sex;
}
//定义类Person2 自己添加无参的构造方法
class Person2{
private int age;
private String name;
private String sex;
public Person2(){
System.out.println("无参构造方法被调用");
}
}
//定义类Person3 有参数的构造方法
class Person3{
private int age;
private String name;
private String sex;
public Person3(String name, String sex, int age ){
this.name = name;
this.sex = sex;
this.age = age;
}
}
//定义类Person4 自己添加无参的构造方法,和有参数的构造方法
class Person4{
private int age;
private String name;
private String sex;
//不带参数的构造函数,可以被重载
public Person4(){
System.out.println("无参构造方法被调用");
}
//带参数对的构造函数
public Person4(String name, String sex, int age ){
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public int getAge(){
return age;
}
}
public class ObjectInit_2 {
public static void main(String[] args) {
//Person1 person1 = new Person1();//编译通过;①实例化Person对象 ②自动调用构造方法Person( )
//Person2 person2 = new Person2();//编译通过;打印: 无参构造方法被调用
// 这样写,编译器会报错,原因是无参构造方法被有参构造方法覆盖,编译器不能提供无参构造方法
//Person3 person3 = new Person3();
//Person4 person4 = new Person4();//编译通过;打印: 无参构造方法被调用
/*Person4 person4 = new Person4("qzz", "man", 18);
System.out.println(person4.getAge());
System.out.println(person4.getName());
System.out.println(person4.getSex());*/
}
}
//this 在无参数构造函数的用法
class Person5{
private int age;
private String name;
private String sex;
private static final int COUNT = 10;//方法区
public Person5() {//不带参数的构造函数 构造函数可以被重载
this("songjaing","man",999);//调用带有三个参数的构造函数
//this("songjaing","man");
System.out.println("Person()");
//count++;
/* this.age = 10;//this:指向当前对象的内存
this.sex = "man";
this.name = "caocao";*/
}
public Person5(String name,String sex,int age) {
System.out.println("Person(name,sex,age)");
this.age = age;//this:指向当前对象的内存
this.sex = sex;
this.name = name;
}
@Override
public String toString() {
return "Person5{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
public class ObjectInit_2_1 {
public static void main(String[] args) {
Person5 person5 = new Person5();
System.out.println( person5 );
}
}
(类名去调用)
static 所修饰的方法或者数据成员不依赖于对象
static{
}
和实例块初始化
{
this.naem = “ddd”
this.sex = “men”
}
//对象的初始化顺序???
//
//
//先静态块初始化(当类里面有 实例成员 和 实例代码块时,同等级别的执行顺序按照他们的顺序来执行)
//
//然后实例代码块初始化
//
//再然后构造函数初始化
class Person6 {
private int age;//数据
private String name;
private String sex;
private static int count; //???????
{
this.name = "gaobo";
this.sex = "superman";
this.age = 18;
System.out.println("instance {} init");//实例块初始化
}
public Person6() {
System.out.println("Person().constrcutor");
}
static {//static所修饰的方法或者数据成员不依赖于对象
count = 10;
//this.name = "gaobo";
System.out.println("static {} init");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
public class ObjectInit_3 {
public static void main(String[] args) {
Person6 person6 = new Person6();
System.out.println(person6);
/* System.out.println("----------------------");
Person6 person7 = new Person6(); // 这几句代码验证了*不管多少个对象,静态代码块只初始化一次 static代码块只出现一次*/
}
}
//输出:
/*
static {} init
instance {} init
Person().constrcutor
Person{age=18, name='gaobo', sex='superman'}
----------------------
instance {} init
Person().constrcutor
Process finished with exit code 0
*/
4.对象的初始化顺序(上面的代码)
先静态块初始化(当类里面有 实例成员 和 实例代码块时,同等级别的执行顺序按照他们的顺序来执行)
然后实例代码块初始化
再然后构造函数初始化
*不管多少个对象,静态代码块只初始化一次
内部类:定义在类结构中的另一个类:类中的定义的成员:
字段
方法
内部类
为什么使用内部类:
1):增强封装,把内部类隐藏在外部类之内,不许其他类访问内部类。
2):内部类能提高代码的可读性和可维护性,把小型类嵌入到外部类中结构上代码更靠近。
3):内部类可以直接访问外部类的成员。
四种内部类:
① 实例内部类: 内部类没有使用static修饰.
② 静态内部类: 内部类使用了static修饰.
③ 局部内部类: 在方法中定义的内部类.
④ 匿名内部类适合于仅使用一次使用的类,属于局部内部类的特殊情况:
外部类的访问修饰符:要么使用public,要么就缺省.
内部类看做是外部类的一个成员,好比字段,那么内部类可以使用public/缺省/protected/private修饰.
还可以是static修饰.
实例内部类(没有static修饰)
面试问题1.实例内部类是否有额外的开销(有)???实例内部类是否有拥有外部内的对象(有)
面试问题2.实例内部类当中是否可以有静态数据成员(有)但是只能是在编译期间确定的值,可以 是static但是必须是final所修饰没有使用static修饰内部类,说明内部类属于外部类的对象,不属于外部类本身.
特点:
1:创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象时,一定存在外部类对象). Outter.Inner in = new Outter().new Inner();
2:实例内部类的实例自动持有外部类的实例的引用,内部类可以直接访问外部类成员.
3:外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问.
4:实例内部类中不能定义静态成员,只能定义实例成员.
5:如果实例内部类和外部类存在同名的字段或方法abc,那么在内部类中:
- this.abc:表示访问内部类成员.
- 外部类.this.abc:表示访问外部类成员.
class OuterClass1{
String name = "Outer.name";
public int data1;
private int data2;
private static int data3;
{
data1 = 999;
data2 = 888;
data3 = 777;
}
public void ooxx(){
System.out.println(this.new InnerClass().age);
}
//实例内部类
class InnerClass{
int age = 17;
String name = "Inner.name";
private int data3 = 100;
public int data5 = 10;
//private static int DATA4 = 1000;error
private static final int DATA4 = 1000;
//private static final int DATA4 = data5;error
public void test(){
String name = "local.name";
System.out.println(name);//访问内部类方法中的的name//如果方法中没有,访问的是内部类的name
System.out.println(this.name);//访问内部类的name
System.out.println(OuterClass1.this.name);//访问外部类的name
}
public void test2(){
System.out.println(data1);//999
System.out.println(data2);//888 OuterClass2.this.
System.out.println(this.data3);//100
System.out.println(OuterClass1.this.data3);//777
System.out.println("InnerClass2().test2()");
}
}
}
public class TestInnerClassDemo2 {
public static void main(String[] args) {
OuterClass1 outerClass = new OuterClass1();
//外部类名.内部类名 引用名 = 外部类对象.new 内部类();
OuterClass1.InnerClass innerClass1 = outerClass.new InnerClass();
innerClass1.test();
System.out.println("-------------------");
innerClass1.test2();
}
}
使用static修饰的内部类.特点:
1):静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例. Outter.Inner in = new Outter.Inner();
2):静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问.
3):在静态内部类中可以定义静态成员和实例成员.
4):测试类可以通过完整的类名直接访问静态内部类的静态成员.
面试问题
1.静态内部类如何访问外部类的非静态数据成员(静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问.)
2.静态内部类是否拥有外部类对对象( 不拥有:静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例)
class OuterClass {
public int data1 = 1;
private int data2 = 2;
private static int data3 = 3;
public OuterClass() {
System.out.println("OuterClass() init");
}
static class InnerClass {
public int data4 = 4;
OuterClass outr;
public InnerClass(OuterClass outr) {
this.outr = outr;
System.out.println("InnerClass()init");
}
public void test2() {
System.out.println(data3);
System.out.println(data4);
System.out.println(outr.data2);//如何访问外部类的非静态数据成员
System.out.println(new OuterClass().data1);// ????
System.out.println("InnerClass().test2()");
}
}
}
public class TestInnerClassDemo1 {
public static void main(String[] args) {
//InnerClass innerClass = new InnerClass();(错误)
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass1 = new OuterClass.InnerClass(outerClass);
System.out.println("-----------------------");
innerClass1.test2();
}
}
局部内部类(打死都不用):
在方法中定义的内部类,其可见范围是当前方法和局部变量是同一个级别.
1):不能使用public,private,protected,static修饰符.
2):局部内部类只能在当前方法中使用.
3):局部内部类和实例内部类一样,不能包含静态成员.
4):局部内部类和实例内部类,可以访问外部类的所有成员.
5):局部内部类访问的局部变量必须使用final修饰(在Java8中是自动隐式加上final,但是依然是常量,不能改变值).
原因:如果当前方法不是main方法,那么当前方法调用完毕之后,当前方法的栈帧被销毁,方法内部的局部变量的空间全部销毁.
然后局部内部类是定义在方法中的,而且在方法中会创建局部内部类对象,而局部内部类会去访问局部变量,当当前方法被销毁的时候,对象还在堆内存,依然持有对局部变量的引用,但是方法被销毁的时候局部变量以及被销毁了.
此时出现:在堆内存中,一个对象引用着一个不存在的数据. 为了避免该问题,我们使用final修饰局部变量,从而变成常量,永驻内存空间,即使方法销毁之后,该局部变量也在内存中,对象可以继续持有.
匿名内部类(Anonymous),是一个没有名称的局部内部类,适合只使用一次的类。
在开发中经常有这样的类,只需要定义一次,使用一次就可以丢弃了,此时:不应该白白定义在一个文件中.
在JavaSE/Android的事件处理中:不同的按钮点击之后,应该有不同的响应操作,首先使用匿名内部类.
特点:
1):匿名内部类本身没有构造器,但是会调用父类构造器.
2):匿名类尽管没有构造器,但是可以在匿名类中提供一段实例初始化代码块,JVM在调用父类构造器后,会执行该段代码.
3):内部类处理可以继承类之外,还可以实现接口.
格式:
new 父类构造器([实参列表]) 或 接口()
{
//匿名内部类的类体部分
}
注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现一个接口。
/**
* 匿名内部类:
*
*/
class OuterClass3 {
public void sayHello() {
System.out.println("hello");
}
}
public class TestInnerClass3 {
public static void test(OuterClass3 out3) {
out3.sayHello();
}
public static void main(String[] args) {
//第一种
new OuterClass3() {
public void sayHello() {
System.out.println("main : hello");
}
}.sayHello();
test(new OuterClass3());
}
}
2018.10.29/周一
by 922