标签(空格分隔): Java
面向对象的特征一:封装与隐藏
一、问题引入
当我们创建一个类的对象以后,我们可以通过“对象.属性”的方法,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和储存范围的制约。除此之外,没有其他约束条件。但是,实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制约束条件的添加。(比如:setlegs())
同时,我们需要避免用户再使用“对象.属性”的方式进行赋值。则需要将属性声明改为私有(private)
--->此时,针对属性就体现了封装性。
public class study1 {
public static void main(String[] args){
Animal a = new Animal();
a.age = 12;
//a.legs = 4;
a.name = "小七";
//a.legs = 4;//legs = 4;(没有走限制/约束)
//a.setLegs(-9);//legs = 0(走约束)
//a.setLegs(4);//legs = 1;
a.legs = -4;//legs 在 Animal 中是 private 访问控制(报错)
a.show();
}
}
class Animal{
int age;
private int legs;//增加权限设置
String name;
//约束
public void setLegs(int l){
if(l >= 0 && l % 2 == 0){
legs = 1;
}else{
legs = 0;
//抛出一个异常(暂时没讲p219)
}
}
public void show(){
System.out.println("name = "+ name+",age = "+ age+",legs = " + legs);
}
}
二、封装性的体现
我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
public class study1 {
public static void main(String[] args){
Animal a = new Animal();
a.age = 12;
//a.legs = 4;
a.name = "小七";
//a.legs = 4;//legs = 4;(没有走限制/约束)
//a.setLegs(-9);//legs = 0(走约束)
//a.setLegs(4);//legs = 1;
//a.legs = -4;//legs 在 Animal 中是 private 访问控制(报错)
//a.show();
System.out.println(a.getLegs());
}
}
class Animal{
int age;
private int legs;//增加权限设置
String name;
//对属性的约束
public void setLegs(int l){
if(l >= 0 && l % 2 == 0){
legs = 1;
}else{
legs = 0;
//抛出一个异常(暂时没讲p219)
}
}
//对属性的获取
public int getLegs(){
return legs;
}
public void show(){
System.out.println("name = "+ name+",age = "+ age+",legs = " + legs);
}
}
三、封装性的体现,需要权限修饰符来配合。
- Java规定的4种权限修饰符(从小到大排序):private、 缺省(什么都不写) 、protected 、public 。
- 4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
修饰类的话,只能使用:缺省 、public - 具体的,4种权限都可以用来修饰类的内部结构,属性、方法、构造器、内部类
- 修饰类的话:只能使用,缺省、public
|修饰符|类内部|同一个包|不同包子类|同一个工程|
|---|---|---|---|
|private|√
|(缺省)|√|√
|protected|√|√|√
|public|√|√|√|√
对于class的权限修饰只可以用public和default(缺省)。
public类可以在任意地方被访问
缺省 类只可以在一个包内部的类访问
-
4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
在study1文件中 public class study1 { private int orderPrivate; int orderDefault; public int orderPublic; private void methodPrivate(){ orderPrivate = 1; orderDefault = 2; orderPublic = 3; } void methodDefault(){ orderPrivate = 1; orderDefault = 2; orderPublic = 3; } public void methodPublic(){ orderPrivate = 1; orderDefault = 2; orderPublic = 3; } } //在Java01文件中 public class Java01 { public static void main(String[] args){ study1 order = new study1(); order.orderPublic = 2; order.orderDefault = 1; //出了Order类之后,私有的结构就不可以调用了 order.orderPrivate = 3;//orderPrivate 在 study1 中是 private 访问控制 order.methodPublic(); order.methodDefault(); //出了Order类之后,私有的结构就不可以调用了 order.methodPrivate();//methodPrivate() 在 study1 中是 private 访问控制 } } //在出了Order类所属的包之后的ordertest文件中 public class Java01 { public static void main(String[] args){ study1 order = new study1(); order.orderPublic = 2; //出了Order类所属的包之后,私有的结构、缺省声明就不可以调用了 order.orderDefault = 1; //出了Order类之后,私有的结构就不可以调用了 order.orderPrivate = 3;//orderPrivate 在 study1 中是 private 访问控制 order.methodPublic(); //出了Order类所属的包之后,私有的结构、缺省声明就不可以调用了 order.methodDefault(); //出了Order类之后,私有的结构就不可以调用了 order.methodPrivate();//methodPrivate() 在 study1 中是 private 访问控制 } }
构造器
类的结构之三:构造器(或构造方法、constructor)的使用
construct:建设构造。 construction: CCB ; constructor:建造者
一、构造器的作用
- 创建对象
- 初始化对象的属性
二、说明:
-
如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
-
定义构造器的格式:权限修饰符 类名(形参列表){}
-
一个类中定义的多个构造器,彼此构成重载
-
一旦我们显式的定义了构造器之后,系统就不再提供默认的空参构造器//去除空参构造器后,空参构造报错
-
一个类中,至少会有一个构造器
//同一个文件夹内(用构造器使用无需考虑与文件名的名字是否相同)
//测试类
public class study1 {
public static void main(String[]args){
//创建类的对象:new + 构造器
Person p = new Person();
p.eat();
p.study();
Person p1 = new Person("Tom");
System.out.println(p1.name);
}
}//类
class Person{
//属性
String name;
int age;//构造器
public Person(){
System.out.println("Person()......");
}public Person(String n){
name = n;
}//方法
public void eat(){
System.out.println("人吃饭");
}
public void study(){
System.out.println("人学习");
}
}
在不同文件中(用构造器使用与文件名相同的的名字)
//Java01文件中进行调用
public class Java01 {
public static void main(String[] args){
//Person p1 = new Person();
study1 p1 = new study1();
//p1.age = 1;//无法调用private私有类
p1.setAge(12);
study1 p2 = new study1("Tom",18);
System.out.println("姓名"+ p2.getName()+";年龄:"+ p2.getAge());
}
}
//study1文件中进行构造
public class study1{
//属性
private String name;
private int age;
//构造器
public study1(){
age = 18;
}
public study1(String n,int a){
name = n;
age = a;
}
public void setAge(int a){
if(a < 0 || a > 130){
System.out.println("传入的是非法数据");
return ;
}
age = a;
}
public void setName(String n){
name = n;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
}
总结:属性复制的先后循序
- 默认初始化
- 显式初始化
- 构造器中赋值
- 通过“对象.方法”或“对象.属性”的方式赋值
以上操作的先后循序:① - ② - ③ - ④
JavaBean
JavaBean是一种Java语言写成的可重用性组件
所谓JavaBean,是指符合如下标准的Java类:
->类是公共的
->有一个无参的公共的构造器
->有属性,且对应的get、set方法
this关键字的使用
-
this可以用来修饰、调用:属性、方法、构造器
-
this修饰属性和方法:
this理解为:当前对象 或 当前正在创建的对象
2.1 在类的方法中,我们可以使用“this.属性”或“this.方法”的方式,调用当前对象属性或方法。但是通常情况下,我们都选择省略“this.”,特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
2.2 在类的构造器中,我们可以使用“this.属性”或“this.方法”的方式,调用当前正在创建的对象或方法。但是通常情况下,我们都选择省略“this.”,特殊情况下,如果构造器的形参和种类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。 -
this调用构造器
①我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中指定的其他构造器
②构造器中不能通过“this(形参列表)”方式调用自己
③如果一个类中有n个构造器,则最多有n-1个构造器使用了“this(形参列表)”
④规定:“this(形参列表)”必须声明在当前构造器的首行
⑤构造器内部,最多只能声明一个“this(形参别表)”,用来调用其他的构造器public class study1 { public static void main(String[] args){ Person p1 = new Person(); p1.setAge(4); System.out.println(p1.getAge()); } } class Person{//属性 private String name; private int age; //构造器 public Person(){ } public Person(int age){ this(); } public Person(String name, int age){ this(age); this.name = name; this.age = age; } public void setAge(int age){ if(age < 0 || age > 130){ System.out.println("传入的是非法数据"); return ; } this.age = age; } public void setName(String name){ this.name = name; } public int getAge(){ return age; } public String getName(){ return name; } }
package关键字
package关键字的使用
- 为了更好地实现项目中的类的管理,提供包的的概念
- 使用package声明类或接口所属的包,声明在源文件的首行
- 包,属于标识符,遵循标识符的命名规范,规范(xxxxyyyyzzzz)、“见名之意”
- 每“.”一次,就代表一层文件名
补充:同一个包下,不能命名同名的接口、类
不同的包下,可以命名同名的接口、类
import关键字的使用
import:导入
- 在源文件中显式的使用import结构导入指定包下的类、接口
- 声明在包的声明和类的声明之间
- 如果需要导入多个结构,则并列写出即可
- 可以使用“xxx.*”的方式,表示可以导入xxx包下的所有结构
- 如果使用的类或接口是Java.lang包下定义的,则可以省略import结构
- 如果使用的类或接口是本包下定义的,可以省略import结构
- 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全名的方式显式
- 使用“xxx.*”方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,任需要显式导入
- import static:导入指定类或接口中静态结构
继承性
一、继承性的好处
①减少了代码的重复,提高了代码的复用性
②便于功能的拓展
③为之后多态性的使用,提供了前提
二、继承性的格式:class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
2.1 :体现:一旦子类A继承了父类B以后,子类A中就获取了父类B中声明的所有属性和方法。特别的,父类中声明为private的属性或方法,子类继承父类以后,任然认为获取了父类中私有的结构。只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
2.2 :子类继承父类以后,还可以声明自己特有的属性或方法,实现功能的拓展性。子类和父类的关系,不同于子集和父集的关系。
extend:延续,拓展
三、Java中关于继承性的规定:
- 一个类可以被多个子类继承
- Java中类的单继承性:一个类只能有一个父类
- 子父类是相对的概念
- 子类直接继承的父类,称为直接父类。子类间接继承的父类,称为间接父类
- 子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
例题:
(1)定义一个ManKind类,包括 成员变量int sex和int salary; 方法void
manOrWoman():根据sex的值显示“man”(sex1)或者“woman”(sex0); 方法void
employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
(2)定义类Kids继承ManKind,并包括 成员变量int yearsOld; 方法printAge()打印yearsOld的值。
(3)定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问 其父类的成员变量及方法。
/定义类KidsTest,在类的main方法中实例化Kids的对象someKid,
用该对象访问 其父类的成员变量及方法。/
public class KidsTest {
public static void main(String[] args) {
Kids someKid = new Kids(12);
someKid.printAge();
someKid.setSalary(0);
someKid.setSex(1);
someKid.employeed();
someKid.manOrWoman();
}
}
/定义类Kids继承ManKind,并包括 成员变量int yearsOld;
方法printAge()打印yearsOld的值。/
public class Kids extends ManKind{
private int yearsOld;
//构造器
public Kids(){
}
public Kids(int yearsOld){
this.yearsOld = yearsOld;
}
//方法
public void printAge(){
System.out.println("I am " +yearsOld + " years old");
}
public int getYearsOld() {
return yearsOld;
}
public void setYearsOld(int yearsOld) {
this.yearsOld = yearsOld;
}
}
/* (1)定义一个ManKind类,包括 成员变量int sex和int salary; 方法void
manOrWoman():根据sex的值显示“man”(sex1)或者“woman”(sex0); 方法void
employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。*/
public class ManKind {
private int sex;
private int salary;
//构造器
public ManKind(){
}
public ManKind(int salary, int sex){
this.sex = sex;
this.salary = salary;
}
//方法
public void manOrWoman() {
if (sex == 1) {
System.out.println("man");
} else if (sex == 0) {
System.out.println("woman");
}
}
public void employeed(){
/*if (salary == 0) {
System.out.println("no job");
} else {
System.out.println("job");
}*/
//或
String jobInfo = (salary == 0)? "no job":"job";
System.out.println(jobInfo);
}
public void setSalary(int salary) {
this.salary = salary;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getSalary() {
return salary;
}
public int getSex() {
return sex;
}
}
方法的重写(override/overwrite)
- 重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
- 应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中同名同参数的方法时,实际执行的是子类重写父类的方法
- 重写的规定: 方法的声明:权限修饰符 返回类型 方法名(形参列表)throws 异常的类型
约定俗成:子类中的叫重写的方法,父类中的叫被重写的方法
①子类重写的方法的方法名和形参列表与父类被重写的方法名和形参列表相同
②子类重写的方法权限修饰符不小于父类被重写的方法的权限修饰符
-》特殊情况:子类不能重写父类中声明为private权限的方法(太小了,无法被发现)
③返回值类型
-》父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
-》父类被重写的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A的子类
-》父类被重写的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的(必须是double)
④子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体在异常处理时候讲)
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)【static静态的:不能被重写】
关键字super
super关键字的使用
- super理解为:父类的
- super可以调用:属性、方法、构造器
- super的使用:
3.1 我们可以在子类的方法或构造器中,通过使用“super.属性”或方“super.方法”的方式,显式调用父类中声明的属性或方法。通常情况下,我们习惯省略“super."
3.2 特殊情况,当子类和父类中定义了同名的属性时,我们想要在子类中调用父类中生命的属性,则必须显式的使用“super.属性”的方式,表明调用的是父类中生命的属性。
3.3 特殊情况,当子类重写了父类的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必 须显式的使用“super.方法”,表明调用的是父类中的被重写的方法。
- super调用构造器
4.1 我们可以在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
4.2 “super(形参列表)”的使用,必须声明在子类构造器的首行。
4.3 我们在类的构造器中,没有显式的声明“this(形参列表)”或“super(形参列表)”,则默认调用的是父类中空参的构造器
4.5 在类的多个构造器中,至少有一个类的构造器中使用了“super(形参列表)”,调用父类中的构造器
子类对象实例化的全过程
- 从结果上来好看:(继承性)
子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。 - 从过程上来看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用父类的构造器,进而调用父类的父类构造器,知道调用了Java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用。
明确,虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。
多态性
-
理解多态性:可以理解为一个事物的多种形态
-
何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用) -
多态的使用:虚拟方法的调用
有了对象的的多态性,我们在编译期,只能调用父类中声明的方法,但在运行期,我们执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边 -
多态性的使用的前提:①类的继承关系②方法的重写
-
对象的多态性:只适用于方法,不适用于属性 (编译和运行都看左边)
父类:Person 子类:Man 父类与子类中均有eat、walk方法 Person p1 = new Man(); p1.eat(); p1.walk();
案例:
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test = new AnimalTest();
test.func(new Dog());
}
public void func(Animal animal){//Animal animal = new Dog
animal.eat();
animal.shout();
}
}
class Animal{
public void eat(){
System.out.println("动物,进食");
}
public void shout(){
System.out.println("动物,叫");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗,爱吃骨头");
}
public void shout(){
System.out.println("狗,汪汪汪");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫,爱吃鱼");
}
public void shout(){
System.out.println("猫,喵喵喵");
}
}
instanceof关键字
强转
知识前瞻:有了对象的多态性以后,内存中实际上加载了子类特有的方法与属性,但是由于变量声明为父类,导致编译时,只能调用父类中声明的属性与方法,子类特有的方法与属性不能调用。
如何才能调用子类特有的属性与方法?
向下转型,使用强制类型转换
Man m1 = (Man) p2;//p2属于Person
m1.earnMoney;
m1.isSmoking = true;
使用强制转换时,可能出现ClassCastException的异常。
instanceof关键字的使用
a instanceof A A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
使用情景:为了避免在向下转型时出现ClassCastException的异常,我们再向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型,如果返回false,不进行向下转型。
如果a instanceof A返回true,则a instanceof B也返回true。
其中,类B是类A的父类。
练习:
class Base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;
//==:对于引用数据类型来说,比较的是两个引用数据的类型变量的地址值是否相同
System.out.println(b == s);//true
System.out.println(b.count);//10
b.display();//20//多态
}
}
- 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法
系统将不可能把父类里的方法转移到子类中,编译看左边,运行看右边 - 对于实例变量则不存在这样的的现象,即使子类里定义了与父类完全相同的实例变量
这个实例变量依旧不可能覆盖父类中定义的实例变量,编译运行都看左边
//练习6
class Person {
protected String name="person";
protected int age=50;
public String getInfo() {
return "Name: "+ name + "\n" +"age: "+ age;
}
}
class Student extends Person {
protected String school="pku";
public String getInfo() {
return "Name: "+ name + "\nage: "+ age + "\nschool: "+ school;
}
}
class Graduate extends Student{
public String major="IT";
public String getInfo()
{
return "Name: "+ name + "\nage: "+ age + "\nschool: "+ school+"\nmajor:"+major;
}
}
public class InstanceTest {
// 建立InstanceTest 类,在类中定义方法
// method(Person e);
// 在method中:
// (1)根据e的类型调用相应类的getInfo()方法。
// (2)根据e的类型执行:
// 如果e为Person类的对象,输出:
// “a person”;
// 如果e为Student类的对象,输出:
// “a student”
// “a person ”
// 如果e为Graduate类的对象,输出:
// “a graduated student”
// “a student”
// “a person”
public static void main(String[] args) {
InstanceTest test = new InstanceTest();
test.method(new Student());
}
public void method(Person e){
//虚拟方法调用
String info = e.getInfo();
System.out.println(info);
if(e instanceof Graduate){
System.out.println("a graduated student");
System.out.println("a student");
System.out.println("a person");
}else if(e instanceof Student){
System.out.println("a student");
System.out.println("a person");
}else if(e instanceof Person){
System.out.println("a person");
}
}
}
object类的使用
Object类是所有Java类的根父类
如果在类的声明中未使用extends关键字指明其父类,则默认父类
为java.lang.Object类
面试题:== 和 equals()区别
一、 回顾==的使用
==:运算符
- 可以使用在基本数据类型变量和引用数据类型变量
- 如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等。(类型不一定要相同) 如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
补充:== 符号使用时,必须保证符号两边的变量类型一致
二、equals()方法的类型:- 是一个方法,而非运算符
- 只能是用于引用数据类型
- Object类中equals()的定义: public boolean equals(Object obj){
return (this == obj);
} 说明:Object类中定义的equals()和== 的作用相同,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体- 像String、Date、file、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同
- 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同。那么我么就需要对Object类的equals进行重写。
重写原则,比较两个对象的实体内容是否相同。
/*1.编写Order类,有int型的orderId,String型的orderName,相应的
getter()和setter()方法,两个参数的构造器,重写父类的equals()方法:
public boolean equals(Object obj),并判断测试类中创建的两个对象是否相等。*/
public class OrderTest {
public static void main(String[] args) {
Order order1 = new Order(1001,"aa");
Order order2 = new Order(1002,"bb");
System.out.println(order1.equals(order2));
Order order3 = new Order(1001,"aa");
System.out.println(order1.equals(order3));
}
}
class Order{
private int orderId;
private String orderName;
//构造器
public Order(int orderId,String orderName){
this.orderId = orderId;
this.orderName = orderName;
}
//方法
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public String getOrderName() {
return orderName;
}
public int orderId(){
return orderId;
}
//重写
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof Object){
Order order = (Order) obj;
return this.orderId == order.orderId && this.orderName == order.orderName;//true
// return this.orderId == order.orderId && this.orderName.equals(order.orderName);//true//基本数据类型用“==”;引用数据类型用“equals”
}
return false;
}
}
例题2:
import java.util.Objects;
//请根据以下代码自行定义能满足需要的MyDate类,在MyDate类中覆盖
// equals方法,使其判断当两个MyDate类型对象的年月日都相同时,结果
// 为true,否则为false。 public boolean equals(Object o)
public class MyDateTest {
public static void main(String[] args) {
MyDate m1 = new MyDate(14, 3, 1976);
MyDate m2 = new MyDate(14, 3, 1976);
if (m1 == m2) {
System.out.println("m1==m2");
} else {
System.out.println("m1!=m2"); // m1 != m2
}
if (m1.equals(m2)) {
System.out.println("m1 is equal to m2");// m1 is equal to m2
} else {
System.out.println("m1 is not equal to m2");
}
}
}
class MyDate{
private int day;
private int month;
private int year;
//构造器
public MyDate(int day,int month,int year){
this.day = day;
this.month = month;
this.year = year;
}
//方法
public void setDay(int day) {
this.day = day;
}
public void setMonth(int month) {
this.month = month;
}
public void setYear(int year) {
this.year = year;
}
public int getDay() {
return day;
}
public int getMonth() {
return month;
}
public int getYear() {
return year;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyDate myDate = (MyDate) o;
return day == myDate.day && month == myDate.month && year == myDate.year;
}
@Override
public int hashCode() {
return Objects.hash(day, month, year);
}
}
Object类中toString()的使用:
-
当我们输出一个对象的引用时,实际上就是在调用当前对象的toString()
-
Object类中toString()定义:
public String toString(){
return getClass().getName()+"@"+Integer.toHexString(hashCode));
} -
像String、Date、File、包装类等都重写了Object类中的toString()方法。
-
自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”。
public class GeometricObject { protected String color; protected double weigh; //构造器 public GeometricObject(){ super(); this.color = "white"; this.weigh = 1.0; } public GeometricObject(String color,double weigh){ this.color = color; this.weigh = weigh; } //方法 public void setColor(String color) { this.color = color; } public void setWeigh(double weigh) { this.weigh = weigh; } public double getWeigh() { return weigh; } public String getColor() { return color; } } import java.util.Objects; public class Circle extends GeometricObject{ private double radius; //构造器 public Circle(){ super(); this.color = "white"; // this.weigh = 1.0;//父类中写了,此时运用了super,无需再写 // this.radius = 1.0; } public Circle(double radius){ super(); // this.color = "white"; // this.weigh = 1.0; this.radius = radius; } public Circle(double radius,String color,double weight){ super(color,weight); // this.radius = radius; // this.weigh = weight; this.color = color; } //方法 public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } public double findArea(){ return 3.14 * radius * radius ; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof Circle) { Circle circle = (Circle) obj; return this.radius == circle.radius; } return false; } // @Override // public int hashCode() { // return Objects.hash(radius); // } @Override public String toString() { return "Circle{" + "radius=" + radius + '}'; } } public class GeometricObjectTest { public static void main(String[] args) { Circle c1 = new Circle(2.3); Circle c2 = new Circle(2.3,"white",2.0); System.out.println("颜色是否相等:"+c1.getColor().equals(c2.getColor())); System.out.println("半径是否相等:"+c1.equals(c2)); System.out.println(c1); System.out.println(c1.toString()); } }
Java中的JUnit单元测试♥
包装类的使用
详情请见:https://blog.csdn.net/qq_39816406/article/details/124062231?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165873601516782425179853%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165873601516782425179853&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-124062231-null-null.142v33new_blog_pos_by_title,185v2control&utm_term=java%E4%B8%AD%E5%8C%85%E8%A3%85%E7%B1%BB%E7%9A%84%E4%BD%BF%E7%94%A8&spm=1018.2226.3001.4187
- Java提供了8种数据类型对应的包装类,使得基本数据类型的变量具有类的特征
- 掌握的,基本数据类型、包装类、String三者之间的相互转换
基本数据类型----->包装类:调用包装类的构造器
包装类------>基本数据类型:调用包装类的xxxValue()
Integer in1 = new Integer(12);
int i1 = in1.intValue;
System.out.println(i1 + 1);
Float f1 = new Float(12.3);
float f2 = f1.floatValue();
System.out.printfln(f2 + 1);
jdk 5.0新特性:自动装箱与自动拆箱
自动装箱:基本数据类型----->包装类
int num2 = 10;
Integer in1 = num2;//自动装箱
boolean b1 = true;
Boolean b2 = b1;//自动装箱
自动拆箱:包装类----->基本数据类型
int num3 = in1;//自动拆包
基本数据类、包装类----->String类型:调用String重载的valueOf(Xxx xxx)
方式一:连接运算
String str1 = num1 + "";
方式二:调用String重载的valueOf(Xxx xxx)
float f1 = 12.3f;
String.valueOf(f1);
String类型----->基本数据类型、包装类:调用包装类parseXxx()
public void test(){
String str1 = "123";
//错误情况
// int num1 = (int)str1;
// Integer in1 = (Integer)str1;
// 可能会报NumberFormatExxception
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
面试题:
public void method1() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128~127范围的整数,如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围内时,可以直接使用数组中的元素,不用再去new了,目的:提高效率
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
Integer x = 128;//相当于new了一个Integer对象
Integer y = 128;
System.out.println(x == y);//false
}
例题:
import java.util.Scanner;
import java.util.Vector;
//利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),
//找出最高分,并输出学生成绩等级。
//提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的
//长度。而向量类java.util.Vector可以根据需要动态伸缩。
//创建Vector对象:Vector v=new Vector();
//给向量添加元素:v.addElement(Object obj); //obj必须是对象
//取出向量中的元素:Object obj=v.elementAt(0);
//注意第一个元素的下标是0,返回值是Object类型的。
//计算向量的长度:v.size();
//若与最高分相差10分内:A等;20分内:B等;
//30分内:C等;其它:D等
public class ScoreTest {
public static void main(String[] args) {
//1 实例化Scanner,用于从键盘获取学生成绩
Scanner scan = new Scanner(System.in);
//2 创建Vector对象:Vector v = new Vec();相当于原来的数组
Vector v = new Vector();
//3 通过for(;;)或while(true)方式,给Vector中添加数组
int maxScore = 0;
for(;;){
System.out.println("请输入学生的成绩(以负数代表输入结束)");
int score = scan.nextInt();
if(score<0){// 当输入是负数时,跳出循环
break;
}
if (score>100){
System.out.println("输入的数据非法,请重新输入");
continue;
}
//3.1 添加操作::v.addElement(Object obj)
// //jdk5.0之前
// Integer inScore = new Integer(score);
// v.addElement(inScore);//多态
//jdk5.0之后
v.addElement(score);//自动装箱
//4 获取学生成绩的最大值
if(maxScore < score){
maxScore = score;
}
}
//5 遍历Vec,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级
char level;
for (int i = 0; i < v.size();i++){
Object obj=v.elementAt(i);
int score = (int) obj;
if(maxScore - score <= 10){
level = 'A';
}else if(maxScore - score <= 20){
level = 'B';
}else if (maxScore - score <= 30){
level = 'C';
}else {
level = 'D';
}
System.out.println("student "+ i + " score is "+ score + ",level is "+ level);
}
}
}
static关键字的使用
- static:静态的;随着类加载而加载
- static可以用来修饰:属性、方法、代码块、内部类
- 使用static修饰属性:静态变量(类变量)
3.1 属性:按是否使用static修饰,又分为:静态变量 VS 非静态变量(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当维修其中一个对象中的非静态变量时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改了的。
3.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载。可以通过“类.静态变量”的方式进行调用。
② 静态变量的加载要早于对象的创建。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。
|④|类变量|实例变量|
|---|---|---|
|类|yes|no|
|对象|yes|yes| - 使用static修饰的方法:静态方法
①随着类的加载而加载,可以通过“类.静态方法”的方法进行调用
|②|静态方法|实例变量|
|---|---|---|
|类|yes|no|
|对象|yes|yes|
③静态方法中,只能调用静态的方法与属性
非静态的方法中:既可以调用非静态的方法或属性,也可以调用静态的方法或属性 - static注意点:
5.1 在静态的方法内,不能使用this关键字、super关键字
5.2 关于静态变量和静态方法的使用,大家都从生命周期的角度去理解。 - 开发中,如何确定一个属性是否需要声明为static的?
->属性可以被多个对象共享的,不会随着对象的不同而不同
->类中的常量也常常声明为static
开发中,如何确定一个方法是否需要声明为static的?
->操作静态属性的方法,通常设置为static的
->工具类中的方法,习惯上声明为static的。比如:Math、Arrays、Collections
案例:求圆的面积
import java.util.concurrent.Callable;
public class CircleTest {
public static void main(String[] args) {
Circle1 c1 = new Circle1();
Circle1 c2 = new Circle1();
Circle1 c3 = new Circle1(2);
System.out.println("c1的ID,"+c1.getId());
System.out.println("c2的ID,"+c2.getId());
System.out.println("c3的ID,"+c3.getId());
System.out.println("c3的面积:"+c3.findArea());
System.out.println("创建的圆的个数:"+Circle1.getTotal());
}
}
class Circle1{
private double radius;
private int id;
private static int total;//记录创建圆的个数
private static int init = 1001;//static声明的属性被所有对象所共享
//构造器
public Circle1(){
id = init++;
total++;
}
public Circle1(double radius){
// id = init++;
// total++;
this();//代替上面的
this.radius = radius;
}
public double findArea(){
return 3.14 * radius * radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public int getId() {
return id;
}
public static int getTotal() {
return total;
}
}
案例:
//编写一个类实现银行账户的概念,包含的属性有“帐号”、“密
//码”、“存款余额”、“利率”、“最小余额”,定义封装这些
//属性的方法。账号要自动生成。
//编写主类,使用银行账户类,输入、输出3个储户的上述信息。
//考虑:哪些属性可以设计成static属性。
public class Account {
private int id;
private String pwd = "000000";
private double balance;
private static double interestRate;
private static double minMoney = 1.0;
private static int init = 1001;//用于自动生成id使用
//构造器
public Account(){
id = init++;
}
public Account(String pwd,double balance){
this();
this.pwd = pwd;
this.balance = balance;
}
//方法
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getId() {
return id;
}
public double getBalance() {
return balance;
}
public static double getMinMoney() {
return minMoney;
}
public static void setMinMoney(double minMoney) {
Account.minMoney = minMoney;
}
public static double getInterestRate() {
return interestRate;
}
public static void setInterestRate(double interestRate) {
Account.interestRate = interestRate;
}
public String toString(){
return
"Account[id"+id+",pwd="+pwd+",balance="+balance+"]";
}
}
public class AccountTest {
public static void main(String[] args) {
Account acct1 = new Account();
Account acct2 = new Account("219038",2000);
Account.setInterestRate(0.012);
Account.setMinMoney(100);
System.out.println(acct1);
System.out.println(acct2);
System.out.println(acct1.getInterestRate());
System.out.println(acct1.getMinMoney());
}
}
单例设计模式
- 所谓单例设计模式,就是采取一定的方法保证在整个的软件体统中,对某个类只能存在一个对象实例。
- 如何实现?饿汉式vs懒汉式
- 区分饿汉式和懒汉式
饿汉式:
坏处:对象加载时将过长
好处:饿汉式是线程安全
懒汉式:
好处:延迟对象的创建
目前写法的坏处:线程不安全
饿汉式:
public class SingletonTest1 {
public static void main(String[] args) {
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);//true
}
}
//饿汉式
class Bank{
//1 私有化类的构造器
private Bank(){
}
//2 内部船家女类的对象
//4 要求此对象也必须声明为静态的
private static Bank instance = new Bank();
//3 提供公共的静态变量的方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
懒汉式:
public class SingletonTest2 {
public static void main(String[] args) {
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1 == order2);
}
}
class Order{
//1 私有化类的变量
private Order(){
}
//2 声明当前对象,没有初始化
//4 此对象也必须声明为static的
private static Order instance = null;
//3声明public、static的返回当前类对象的方法
public static Order getInstance(){
if(instance == null){
instance = new Order();
}
return instance;
}
}
代码块
- 代码块的作用,用来初始化类、对象
- 代码块如果有修饰的话,只能使用static
- 分类:静态代码块 vs 非静态代码块
- 静态代码块
——>内部可以有输出语句
——>随着类的加载而执行,而且只执行一次
——>作用:初始化
——>如果一个类中定义了多个静态代码块,则按声明的先后循序执行
——>静态代码块的执行要优于非静态代码块的执行
——>静态代码块内只能调用静态的方法与属性,不能调用非静态的结构 - 非静态代码块
——>内部可以有输出语句
——>随着对象的创建而执行
——>每创建一个对象,就执行一次非静态代码块
——>作用:可以在创建对象时,对对象的属性等进行初始化
——>如果一个类中定义了多个非静态代码块,则按声明的先后循序执行
——>非静态代码块内可以调用静态的属性,静态的方法,或非静态的属性、非静态的方法
对属性可以赋值的位置:
①默认初始化
②显示初始化
③构造器中初始化
④有了对象以后,可以通过“对象.属性”或“对象.方法”的方式,进行赋值
⑤在代码块中赋值
执行的先后循序:① - ② / ⑤ - ③ - ②
public class BlockTest {
public static void main(String[] args) {
String desc = Person.desc;
System.out.println(Person.desc);
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.age);
}
}
class Person{
//属性
String name;
int age;
static String desc = "我是一个人";
//构造器
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//代码块
//static的代码块
static {
System.out.println("Hello,static block");
//调用静态结构
desc = "我是一个爱学习的人";
//不能调用非静态结构
// eat();
// name = "Tom";
}
static {
System.out.println("Hello,static block-2");
}
//非static的代码块
{
System.out.println("Hello,block");
//调用非静态结构
age = 1;
eat();
//调用静态结构
desc = "非static的代码块调用静态结构";
}
//方法
public void eat(){
System.out.println("吃饭");
}
}
final:最终的
-
final可以修饰的结构:类、方法、变量
-
final 用来修饰一个类:此类不能被其他类所继承
比如说:String类、System类、StringBuffer类 -
final 用来修饰方法:表明此方法不可以被重写
public class FinalTest { public static void main(String[] args) { } } class AA{ public final void show(){ } } class BB extends AA{ public final void show(){//报错 } }
-
final 用来修饰变量:此时的“变量”就称为一个常量
4.1 final修饰属性:显式初始化、代码块中初始化、构造器中初始化
4.2 final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此形参
static final 用来修饰:全局常量public class FinalTest { //显式初始化 final int WIDTH = 0; final int LEFT; final int RIGHT; // final int DOWN; //代码块中初始化 { LEFT = 1; } //构造器中初始化 public FinalTest(){ RIGHT = 2; } public FinalTest(int n){ RIGHT = n; } // public void setDOWN(int down){//方法里调用//不行 // this.DOWN = down; // } public static void main(String[] args) { // FinalTest test = new FinalTest(); // test.setDOWN(3); } }
抽象类与抽象方法
abstract关键字的使用
-
abstract:抽象的
-
abstract可以修饰的结构:类、方法
-
abstract修饰类抽象类
——>此类不能实例化(不能造对象)
——>抽象类中一定有构造器,便于子类实例化调用(涉及,子类对象实例化的全过程)
——>开发中,都会提供抽象类的之类,让子类对象实例化,完成相关操作 -
abstract修饰方法:抽象方法
——>抽象方法只有方法的声明,没有方法体
——>包含抽象方法的类,一定是一个抽象类,反之,抽象类中可以没有抽象方法。
——>若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰public class AbstractTest { public static void main(String[] args) { //一旦Person类抽象了,就不可实例化 // Person p1 = new Person(); // p1.eat(); } } abstract class Person{ String name; int age; //构造器 public Person(){ } public Person(String name, int age){ this.age = age; this.name = name; } //方法 /*//不是抽象方法 public void eat(){ }*/ //抽象方法 public abstract void eat(); public void weak(){ System.out.println("人走路1"); } } /* class Student extends Person{ public Student(String name, int age){ super(name, age); } public void eat(){ System.out.println("学生应该多吃好吃的食物"); } }*/ //或 abstract class Student extends Person{ public Student(String name, int age){ super(name, age); } }
abstract使用上的注意点:
- abstract不能用来修饰:属性、构造器等结构
- abstract不能用来修饰私有方法、静态方法、final的方法、final的类
案例:
public abstract class Employee {
private String name;
private int id;
private double salary;
public Employee(){
super();
}
public Employee(String name,int i,double salary){
this.id = id;
this.name = name;
this.salary = salary;
}
public abstract void work();
}
public class CommonEmployee extendspublic class EmployeeTest {
public static void main(String[] args) {
//多态
Employee manager = new Manager("库克",1001,5000,50000);
manager.work();
CommonEmployee commonEmployee = new CommonEmployee();
commonEmployee.work();
}
}
Employee{
public void work(){
System.out.println("员工在一线车间生产产品");
}
}
public class Manager extends Employee{
private double bonus;//奖金
public Manager(double bonus){
super();
this.bonus = bonus;
}
public Manager(String name,int id,double salary,double bonus){
super(name,id,salary);
this.bonus = bonus;
}
@Override
public void work() {
System.out.println("管理员工,提高效率");
}
}
模板方法
接口
接口的使用:
-
接口使用interface来定义
-
Java中,接口和类是并列的两种结构
-
如何定义接口:接口的成员
3.1 JDK7及以前,只能定义全局变量和抽象方法
——>全局变量:public static final的,但是书写时,可以省略不写
——>抽象方法:public abstract的 -
接口中不能定义构造器!意味着接口不可以实例化
-
Java开发中,接口通过让类去实现(implements)的方法来实现
如果实现类的覆盖了接口的所有抽象方法,则此实现类就可以实例化
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍是一个抽象类 -
Java类可以实现多个接口——>弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD,EE{} -
接口与接口之间可以继承
-
接口的具体使用,体现多态性
-
接口可以看作是一种规范
public class InterfaceTest {
public static void main(String[] args){
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);Plane plane = new Plane(); plane.fly(); }
}
interface Attackable{
void attack();
}
interface Flyable{
//全局变量
public static final int MAX_SPEED = 7900;//第一宇宙速度
int MIN_SPEED = 1;//可以省略public static final int,与省略之前一样//抽象方法 public abstract void fly(); void stop();//省略了public abstract
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("通过引擎起飞");
}@Override public void stop() { System.out.println("驾驶员减速停止"); }
}
abstract class Kite implements Flyable{
@Override public void fly() { }
}
class Bullet implements Flyable,Attackable,CC{
@Override public void attack() { } @Override public void fly() { } @Override public void stop() { } @Override public void method1() { } @Override public void method2() { }
}
//***********************
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{}
接口的使用
-
接口使用上也满足多态性
-
接口,实际上就是定义了一种规范
-
开发中,体会面向接口编程
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
com.transferDate(flash);//2. 创建了接口的非匿名实现类的匿名对象 com.transferDate(new Printer()); //3. 创建了接口的匿名实现类的非匿名对象 USB phone = new USB() { @Override public void start() { System.out.println("手机开始工作"); } @Override public void stop() { System.out.println("手机结束工作"); } }; com.transferDate(phone); //4. 创建了接口的匿名实现类的匿名对象 com.transferDate(new USB() { @Override public void start() { System.out.println("MP3开始工作"); } @Override public void stop() { System.out.println("MP3结束工作"); } }); }
}
class Computer{
public void transferDate(USB usb){//USB usb = new Flash();
usb.start();
System.out.println("----------");
usb.stop();
}
}
interface USB{
void start();void stop();
}
class Flash implements USB{
@Override public void start() { System.out.println("U盘开启工作"); } @Override public void stop() { System.out.println("U盘结束工作"); }
}
class Printer implements USB{@Override public void start() { System.out.println("打印机开启工作"); } @Override public void stop() { System.out.println("打印机结束工作"); }
}
接口的应用:代理模式
面试题:
抽象类与接口有哪些异同
排错
题1
interface A{
int x = 0;
}
class B {
int x = 1;
}
class C extends B implement A{
public void pX(){
//System.out.println(x);//不明确的调用
System.out.println(Super.x);//1
System.out.println(A.x);//A接口是全局的,直接调
}
public static void main(String[] args){
new C().pX();
}
}
题2
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable,
Bounceable {
Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name = name;
}
public void play() {
ball = new Ball("Football");
System.out.println(ball.getName());
}
}
Java8 中的新特性
Subclass s = new SubClass();
知识点1:接口中定义的静态方法,只能通过接口来调用
CompareA.method1();
知识点2:通过实现类的现象,可以调用接口中默认方法
如果实现类重写了接口的默认方法,调用时,仍然调用的是重写以后的方法
s.method2();
知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。——>类优先原则
知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。——>接口冲突。这就需要我们必须在实现类中重写此方法
内部类
-
Java中允许将一个类A声明在另外一个类B中,则类A就是内部类,称B为外部类
-
内部类的分类:成员内部类(静态的、非静态的) vs 局部内部类(方法内、代码块内、结构器内)
-
成员内部类
一方面:作为外部类的成员:
——>调用外部类的结构
——>可以被static修饰
——>可以被4种不同的权限修饰
另一方面:作为一个类:
——>类内可以定义属性、方法、构造器等
——>可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
——>可以被abstract修饰, -
关注如下3个问题
4.1 如何实例化成员内部类的对象
4.2 如何在成员内部类中区分调用外部类的结构
4.3 开发中局部内部类的使用 见《InnerClassTest1.java》public class InnerClassTest { public static void main(String[] args) { //创建Dog实例(静态的成员内部类) Person.Dog dog = new Person.Dog(); dog.Show(); //创建Bird实例(静态的成员内部类) // Person.Bird bird = new Person.Bird();//错误的 Person p = new Person(); Person.Bird bird = p.new Bird(); bird.sing(); System.out.println("__________"); bird.display("黄鹂"); } } class Person{ int age; String name = "向明"; public void eat(){ System.out.println("人,吃饭"); } //静态成员内部类 // abstract static class Dog{ static class Dog{ int age; String name = "汪汪"; public void Show() { System.out.println("小狗爱吃骨头"); } } //非静态成员内部类 // final class Bird{ class Bird{ String name = "杜鹃"; public Bird(){ } public void sing(){ System.out.println("我是一只小小鸟"); // Person.this.eat(); eat(); } public void display(String name){ System.out.println(name);//方法的形参 System.out.println(this.name);//内部类的属性 System.out.println(Person.this.name);//外部类的属性 } } public void method(){ //局部内部类 class AA{ } } { //局部内部类 class BB{ } } public Person(){ //局部内部类 class CC{ } } }
--
public class InnerClassTest1 {
//开发中很少见
public void method(){
//局部内部类
class AA{
}
}
/*//返回一个实现了Comparable接口的类对象
public Comparable getComparable(){
//创建一个实现了Ccomparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
// }
//
// return new MyComparable();
//方式二:
return new Comparable() {
@Override
public int compareTo(Object o) {
return 0;
}
};
}*/
}
在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:num)要求此变量声明为final的。
public class InnerClassTests {
public void method(){
//局部变量
//final int num = 10;
int num = 10;//在内部类中,是final(final省略)
class AA{
public void show(){
// num = 20;//不能这么做//传入的是副本,不是本身,能用不能改
System.out.println(num);
}
}
}
}
标签:Java,int,void,基础,System,面向对象,println,public,out
From: https://www.cnblogs.com/fengmian13wl/p/18348582