1.Java类及类的成员
(1)类是抽象的,而对象是实例
(2)类成员:属性(类中的成员变量)、方法(类中的成员方法)
属性=成员变量=field=域、字段
方法=成员方法=函数=method
创建类的对象=类的实例化=实例化类
ENG
public class PersonTest{//测试类
public static void main(String[] args){
//创建person类的对象
Person p1 = new Person();
//调用对象的结构、属性、方法
//
p1.name="TOM";
p1.ismale=true;
System.out.println(p1.name);
//调用对象、方法
p1.eat();
p1.language("hello");
}
}
class Person{//类
//属性
String name;
int age ;
boolean ismale;
//方法
public void eat(){
String food="饼干";//局部变量
System.out.println("我们吃"+food);
}
public void talk(String language){//language:形参,也是局部变量
System.out.println("我们使用"+language+"进行交流");
}
}
属性 vs 局部变量
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)
局部变量:加载到栈空间
方法
方法的声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
1 关于权限修饰符:
默认方法的权限修饰符先都使用public <br /> Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说
2 返回值类型: 返回值 vs 没返回值
如果方法返回值,则必须在方法声明时,指定返回值的类型。
同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
如果方法没返回值,则方法声明时,使用void来表示。通常,没返回值的方法中,就不需要使用return.但是, 如果使用的话,只能“return;”表示结束此方法的意思。
匿名对象
1.理解:我们创建的对象,没有显式的赋给一个变量名。即为匿名对象
2.特征:匿名对象只能调用一次。
3.使用:如下 ```java public class InstanceTest { public static void main(String[] args) { //匿名对象new Phone().sendEmail();
new Phone().playGame();
new Phone().price = 1999; new Phone().showPrice();//0.0 //** PhoneMall mall = new PhoneMall(); //匿名对象的使用 mall.show(new Phone());
} }
class PhoneMall{ public void show(Phone phone){ phone.sendEmail(); phone.playGame(); } }
class Phone{ double price;//价格 public void sendEmail(){ System.out.println(“发送邮件”); } public void playGame(){ System.out.println(“玩游戏”); } public void showPrice(){ System.out.println(“手机价格为:” + price); }
}
<a name="l87m8"></a>
### 类之间的调用
```java
//自定义数组的工具类
public class ArrayUtil {
// 求数组的最大值
public int getMax(int[] arr) {
}
}
public class ArrayUtilTest {
public static void main(String[] args) {
ArrayUtil util = new ArrayUtil();//定义了一个类变量
int[] arr = new int[]{32,34,32,5,3,54,654,-98,0,-53,5};
int max = util.getMax(arr);//调用另一个类中的方法
System.out.println("最大值为:" + max);
}
}
方法重载
定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。 *
总结:”两同一不同”:同一个类、相同方法名
参数列表不同:参数个数不同,参数类型不同
3. 如何判断是否构成方法的重载?
严格按照定义判断:两同一不同。跟方法的权限修饰符、返回值类型、形参变量名、方法体都没关系!
可变个数形参
1 可变个数形参的格式:数据类型 … 变量名
2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
public void show(String s){
System.out.println("show(String)");
}
//重载
public void show(String ... strs){}
4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
public void show(String ... strs){
}
//不能与上一个方法同时存在,两者基本等同
// public void show(String[] strs){
// }
//调用1
test.show("hello");
test.show("AA","BB","CC");
//调用2
test.show(new String[]{"AA","BB","CC"});
5 可变个数形参在方法的形参中,必须声明在末尾
public void show(String...strs,int a){}//这是错误的
public void show(int a,String...strs){}
6 可变个数形参在方法的形参中,最多只能声明一个可变形参。
public void show(String...strs,int...s){}//wrong
方法参数的值传递机制(很重要)
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
- 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
【例题1】
练习5(并非参数传递)
public class Test{
public static void main(String[] args){
int a=1;
int b=2;
method(a,b);//仅打印出a=100,b=200
System.out.println("a="+a);
System.out.println("b="+b);
}
//我的答案
public void method(){
}
}
为什么不都是地址值,是因为Println()有重构,println(char[])为打印数组
练习6
//Circle类
public class Circle{
double radius;
public findArea(){
return radius*radius*Math.PI;
}
}
//PassObject类
public class PassObject{
public void printAreas(Circle c,int time){
double area;
int i;
System.out.println("Radius\t\tArea");
for(i=1;i<=time;i++){
c.radius=i;
area=c.findArea();
System.out.println(i+"\t\t"+area);
}
//error,按照题应该再加一行
c.radius=i;
}
public void main(String[] args){
//printAreas test = new printAreas(Circle c,5);
printAreas test = new printAreas();
c= new Circle();
test.printAreas(c,5);
//int time =5;
// int radius_now=test.i;
System.out.println("now radius is:"+c.radius);
}
}
特殊的String
String不是基本数据类型,属于引用数据类型
String s1,s1是字符串常量值,不可以更改.
结果为hello
public class ValueTransferTest {
public static void main(String[] args) {
String s1 = "hello";
//String s1 = new String{"hello"}
ValueTransferTest test = new ValueTransferTest();
test.change(s1);
System.out.println(s1);//hi~~
}
public void change(String s){//虽然传递了地址,但是s开辟了新的地址。
s = "hi~~";
}
}
类的成员—构造器
类的结构之三:构造器(或构造方法、constructor)的使用
construct:建设、建造。 construction:CCB constructor:建设者
一、构造器的作用:
1.创建对象
2.初始化对象的信息
二、说明:
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
class Person{
//系统默认空参的构造器
public Person(){
}
}
2.定义构造器的格式:权限修饰符 类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
5.一个类中,至少会有一个构造器。
public class PersonTest {
public static void main(String[] args) {
//创建类的对象:new + 构造器
Person p = new Person();
p.eat();
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 Person(String n,int a){
name = n;
age = a;
}
//方法
public void eat(){
System.out.println("人吃饭");
}
public void study(){
System.out.println("人可以学习");
}
}
练习9
//自己写的,不太合格
import java.util.Scanner;
public class TriAngle{
private double base;
private double height;
public void getbase(){
return base;
}
public void getheight(){
return height;
}
public TriAngle(){
}
public TriAngle(double m,double n){
base=m;
height=n;
//return 0.5*base*height//构造里面不能有返回
}
}
public class TriAngleTest{
//
public static void main(String[] args){
}
//
System.out.println("请输入三角形低长:");
double base = scan.nextDouble();
System.out.println("请输入三角形高:");
double height = scan.nextDouble();
TriAngle test = new TriAngle(base,height);
}
//参考答案
/*
* 编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。
* 此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
*/
public class TriAngle { //angle:角 angel:天使
private double base;//底边长
private double height;//高
public TriAngle(){
}
public TriAngle(double b,double h){
base = b;
height = h;
}
public void setBase(double b){
base = b;
}
public double getBase(){
return base;
}
public void setHeight(double h){
height = h;
}
public double getHeight(){
return height;
}
}
///////////////////////////////////////////
package com.atguigu.exer1;
public class TriAngleTest {
public static void main(String[] args) {
TriAngle t1 = new TriAngle();
t1.setBase(2.0);
t1.setHeight(2.4);
// t1.base = 2.5;//The field TriAngle.base is not visible
// t1.height = 4.3;
System.out.println("base : " + t1.getBase() + ",height : " + t1.getHeight());
TriAngle t2 = new TriAngle(5.1,5.6);
System.out.println("base : " + t2.getBase() + ",height : " + t2.getHeight());
}
}
类的成员—代码块(或初始化块)
- 代码块的作用:用来初始化类、对象
2. 代码块如果有修饰的话,只能使用static.
3. 分类:静态代码块 vs 非静态代码块
静态代码块 | 非静态代码块 |
---|---|
- 内部可以有输出语句 - 随着类的加载而执行,而且只执行一次 - 作用:初始化类的信息 - 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行 - 静态代码块的执行要优先于非静态代码块的执行 - 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构 |
- 内部可以有输出语句 - 随着对象的创建而执行,每创建一个对象,就执行一次非静态代码块 - 作用:可以在创建对象时,对对象的属性等进行初始化 - 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行 - 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法 |
4、由父及子 静态先行=>package com.atguigu.java3;day14,son.java
对属性可以赋值的位置:
①默认初始化
②显式初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过”对象.属性”或”对象.方法”的方式,进行赋值
- 执行的先后顺序:① - ② / ⑤ - ③ - ④
```java
public class OrderTest {
public static void main(String[] args) {
} }Order order = new Order();
System.out.println(order.orderId);
class Order{
//显性初始化
int orderId = 3;
//在代码块中赋值
{
orderId = 4;
}
//结果为4,这两种方法谁先写谁先赋值
}
<a name="b6LJq"></a>
## 2.面向对象的三大特征
<a name="ll2Xm"></a>
### 封装和隐藏
面向对象的特征一:封装与隐藏 3W:what? why? how? <br /> 一、问题的引入:<br /> 当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到<br /> 属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值<br /> * 加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs())<br /> * 同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private).<br /> * -->此时,针对于属性就体现了封装性。<br /> * <br /> * 二、封装性的体现:<br /> * 我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值<br /> * <br /> * 拓展:封装性的体现:① 如上 ② 不对外暴露的私有的方法 ③ 单例模式 ...<br /> * <br /> * <br /> * 三、封装性的体现,需要权限修饰符来配合。<br /> * 1.Java规定的4种权限(从小到大排列):private、缺省、protected 、public <br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/21675987/1622180048097-86f76770-a970-4a0a-aabe-3acc2e464faf.png#clientId=uc1422c28-c933-4&from=paste&height=165&id=u90b0310f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=165&originWidth=645&originalType=binary&ratio=1&size=21747&status=done&style=none&taskId=ub2ba91b2-574c-42a9-8994-845b87ba255&width=645)<br /> * 2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类<br /> * 3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类<br /> * 修饰类的话,只能使用:缺省、public<br /> * <br /> * 总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。<br /> * <br /> */<br />
```java
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "大黄";
// a.age = 1;
// a.legs = 4;//The field Animal.legs is not visible
a.show();
// a.legs = -4;
// a.setLegs(6);
a.setLegs(-6);
// a.legs = -4;//The field Animal.legs is not visible
a.show();
System.out.println(a.name);
}
}
//Animal属性的封装
class Animal{
String name;
private int age;
//二、封装性的体现:
// 我们将类的属性xxx私有化(private),同时,
//提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
private int legs;//腿的个数
//对属性的设置
public void setlegs(int l){
if(l>=0&&l%2==0){
lengs=l;
}else{
legs = 0;
// 抛出一个异常(暂时没有讲)
}
}
//对属性的获取
public int getlegs(){
return legs;
}
}
继承性
一、继承性的好处: ① 减少了代码的冗余,提高了代码的复用性
② 便于功能的扩展
③ 为之后多态性的使用,提供了前提
二、继承性的格式:
class A extends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
2.1体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。
* 只有因为封装性的影响,使得子类不能直接调用父类的结构而已。2.2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
子类和父类的关系,不同于子集和集合的关系。
extends:延展、扩展
三、Java中关于继承性的规定:
1.一个类可以被多个子类继承。
2.Java中类的单继承性:一个类只能有一个父类
3.子父类是相对的概念。
4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
四、 1. 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类
2. 所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
3. 意味着,所有的java类具有java.lang.Object类声明的功能。public class Creature {
public void breath(){
System.out.println("呼吸");
}
}
public class Person extends Creature{
String name;
private int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃饭");
sleep();
}
private void sleep(){
System.out.println("睡觉");
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
方法的重写(override / overwrite)
| 1.重写 | 子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作 | | —- | —- | | 2.应用 | 重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。 | | 3. 重写的规定 | 方法的声明
权限修饰符 返回值类型 方法名(形参列表) {
//方法体
}
权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
//方法体
} | | | 约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法 | | | ① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同 | | | ② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符
>特殊情况:子类不能重写父类中声明为private权限的方法 | | | ③ 返回值类型:
>父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
>父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double) | | | ④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲) | | | 子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写) |面试题:区分方法的重载与重写 ```java public class Person {
String name; int age; public Person(){
} public Person(String name,int age){ this.name = name; this.age = age; }void eat(){ System.out.println(“吃饭”); } public void walk(int distance){ System.out.println(“走路,走的距离是:” + distance + “公里”); show(); eat(); }
private void show(){ System.out.println(“我是一个人”); }
public Object info(){ return null; }
public double info1(){ return 1.0; }
}
```java
public class Student extends Person{
String major;
public Student(){
}
public Student(String major){
this.major=major;
}
public void study(){
System.out.println("学习。专业是:" + major);
}
public void eat(){//重写了父类的方法
System.out.println("学生应该吃好吃的");
}
//并非重写,因为父类show方法是private,这里是子类的新方法
public void show(){
System.out.println("我是一个学生");
}
}
public class PersonTest{
Student s= new Student("计算机");
s.eat();//执行了子类的方法
s.walk(10);
s.study();
}
多态
1.多态性的理解:
2.何为多态性:
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
Person p = new Man();
Object obj = new Date();
3.多态性的使用:虚拟方法调用
- 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。
-
4.多态性的使用前提:
5.多态性的应用举例:
```java 举例一: public void func(Animal animal){//Animal animal = new Dog();
animal.eat();
animal.shout();
} 举例二: public void method(Object obj){
} 举例三: class Driver{
public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection();
//规范的步骤去操作数据
// conn.method1(); // conn.method2(); // conn.method3();
}
}
<a name="EcL3A"></a>
#### 6.多态性使用的注意点:
对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
************************************************************
<a name="DJqyn"></a>
#### 7.关于向上转型与向下转型:
**7.1 向上转型**:多态<br />**7.2 向下转型**:<br />**7.2.1 为什么使用向下转型:**<br />有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。如何才能调用子类特的属性和方法?使用向下转型。<br />**7.2.2 如何实现向下转型:**<br />使用强制类型转换符:()<br />**7.2.3 使用时的注意点:**<br />① 使用强转时,可能出现ClassCastException的异常。<br />② 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。<br />**7.2.4 instanceof的使用:**<br />① a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。<br />② 如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。<br />③ 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/21675987/1622598201602-beb2a964-aeab-44d0-ab62-d9c2853f5422.png#clientId=u0a411b43-71c3-4&from=paste&height=141&id=ue34c659e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=141&originWidth=338&originalType=binary&ratio=1&size=50329&status=done&style=none&taskId=u00240c80-5218-4ef0-9009-b9be03417f6&width=338)<br />7.2.5 图示:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/21675987/1622597454535-143ee3f9-bf0c-40dc-b23b-e2f851c5d8c9.png#clientId=u0a411b43-71c3-4&from=paste&height=278&id=WJtPK&margin=%5Bobject%20Object%5D&name=image.png&originHeight=421&originWidth=700&originalType=binary&ratio=1&size=36842&status=done&style=none&taskId=uac8cf54c-4f5d-40b2-95d2-8b88c314ea8&width=462)
```java
//问题一:编译时通过,运行时不通过
Person p4 = new Person();
Man m4 =(Man)p4;
//问题二:编译通过,运行时也通过
Object obj = new Woman();
Person p = (Person)obj;
//问题三:编译不通过
Man m=new Woman();
8. 面试题:
8.1 谈谈你对多态性的理解?
① 实现代码的通用性。
② Object类中定义的public boolean equals(Object obj){ }
JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)
③ 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)
8.2 多态是编译时行为还是运行时行为?
3.其它关键字
this的使用
1.this可以用来修饰、调用:属性、方法、构造器
2.this修饰属性和方法:
this理解为:当前对象 或 当前正在创建的对象
2.1 在类的方法中,我们可以使用”this.属性”或”this.方法”的方式,调用当前对象属性或方法。但是,
通常情况下,我们都选择省略”this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式
的使用”this.变量”的方式,表明此变量是属性,而非形参。
2.2 在类的构造器中,我们可以使用”this.属性”或”this.方法”的方式,调用当前正在创建的对象属性或方法。
但是,通常情况下,我们都选择省略”this.”。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式
的使用”this.变量”的方式,表明此变量是属性,而非形参。
3. this调用构造器
- 我们在类的构造器中,可以显式的使用”this(形参列表)”方式,调用本类中指定的其他构造器
- 构造器中不能通过”this(形参列表)”方式调用自己
- 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了”this(形参列表)”
- 规定:”this(形参列表)”必须声明在当前构造器的首行
构造器内部,最多只能声明一个”this(形参列表)”,用来调用其他的构造器 ```java public class PersonTest { public static void main(String[] args) {
Person p1 = new Person();
p1.setAge(1);
System.out.println(p1.getAge());
p1.eat();
System.out.println();
Person p2 = new Person("Jerry",20);
System.out.println(p2.getAge());
} }
class Person{
private String name;
private int age;
public Person(){
// this.eat(); String info = “Person初始化时,需要考虑如下的1,2,3,4…(共40行代码)”; System.out.println(info); }
public Person(String name){
this();//调用空参
this.name = name;
}
public Person(int age){
this();//调用空参
this.age = age;
}
public Person(String name,int age){
this(age);//调用Person(age)
this.name = name;
//this.age = age;
//Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public void eat(){
System.out.println("人吃饭");
this.study();
}
public void study(){
System.out.println("人学习");
}
}
<a name="rQK7P"></a>
#### 练习11
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21675987/1622188625173-3e627d68-8214-4517-893e-9113224be63e.png#clientId=u89f2228f-42c8-4&from=paste&height=339&id=ucfcc138f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=339&originWidth=585&originalType=binary&ratio=1&size=56690&status=done&style=none&taskId=u69486f87-6889-4847-b591-9f64070c957&width=585)
```java
public class Boy{
private String name;
private int age;
public void setName(String i){
name=i;
}
public String getName(){
return getname;
}
public void setAge(int i){
age=i;
}
public int getAge(){
return age;
}
public void marry(Girl girl){
System.out.println("我想娶" + girl.getName());
}
public void shout(){
if(this.age >= 22){
System.out.println("你可以去合法登记结婚了!");
}else{
System.out.println("先多谈谈恋爱~~");
}
}
public Boy (){
}
public Boy(String name, int age) {
this.name = name;
this.age = age;
}
}
/////////////////////////////////////////////////////////////////////
public class Girl{
private String name;
private int age;
public void setName(String i){
name=i;
}
public String getName(){
return getname;
}
public void marry(Boy boy){
System.out.println("我想嫁给" + boy.getName());
boy.marry(this);//this代表当前对象
}
/**
*
* @Description 比较两个对象的大小
* @author shkstart
* @date 2019年1月18日下午4:02:09
* @param girl
* @return 正数:当前对象大; 负数:当前对象小 ; 0:当前对象与形参对象相等
*/
public int compare(Girl girl){
// if(this.age > girl.age){
// return 1;
// }else if(this.age < girl.age){
// return -1;
// }else{
// return 0;
// }
return this.age - girl.age;
}
public Girl (){
}
public Girl(String name, int age) {
this.name = name;
this.age = age;
}
}
public class BoyGirlTest {
public static void main(String[] args) {
Boy boy = new Boy("罗密欧", 21);
boy.shout();
Girl girl = new Girl("朱丽叶", 18);
girl.marry(boy);
Girl girl1 = new Girl("祝英台",19);
int compare = girl.compare(girl1);
if(compare > 0){
System.out.println(girl.getName() + "大");
}else if(compare < 0){
System.out.println(girl1.getName() + "大");
}else{
System.out.println("一样大");
}
}
}
关键字package
1.为了更好的实现项目中类的管理,提供包的概念
2.使用package声明类或接口所属的包,声明在源文件的首行
3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”
4.每”.”一次,就代表一层文件目录。
package com.atguigu.java2;
- 补充:同一个包下,不能命名同名的接口、类。
* 不同的包下,可以命名同名的接口、类。MVC
关键字import
*1. 在源文件中显式的使用import结构导入指定包下的类、接口import java.util.*;
- 声明在包的声明和类的声明之间
3. 如果需要导入多个结构,则并列写出即可
4. 可以使用”xxx.“的方式,表示可以导入xxx包下的所有结构
5. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6. 如果使用的类或接口是本包下定义的,则可以省略import结构
7. 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
8. 使用”xxx.“方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入
9. import static:导入指定类或接口中的静态结构:属性或方法。super
1.super 关键字可以理解为:父类的
2.可以用来调用的结构:属性、方法、构造器
3.super调用属性、方法:
3.1 我们可以在子类的方法或构造器中。通过使用”super.属性”或”super.方法”的方式,显式的调用父类中声明的 属性或方法。但是,通常情况下,我们习惯省略”super.”
3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用”super.属性”的方式,表明调用的是父类中声明的属性。
3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用”super.方法”的方式,表明调用的是父类中被重写的方法。
- 声明在包的声明和类的声明之间
4.super调用构造器:
4.1 我们可以在子类的构造器中显式的使用”super(形参列表)”的方式,调用父类中声明的指定的构造器
4.2 “super(形参列表)”的使用,必须声明在子类构造器的首行!
4.3 我们在类的构造器中,针对于”this(形参列表)”或”super(形参列表)”只能二一,不能同时出现
4.4 在构造器的首行,没显式的声明”this(形参列表)”或”super(形参列表)”,则默认调用的是父类中空参的构造器:super()
4.5 在类的多个构造器中,至少一个类的构造器中使用了”super(形参列表)”,调用父类中的构造器
static
static关键字的使用
1.static:静态的
2.static可以用来修饰:属性、方法、代码块、内部类
3.使用static修饰属性:静态变量(或类变量)
3.1 属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致
其他对象调用此静态变量时,是修改过了的。
3.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载。可以通过”类.静态变量”的方式进行调用
② 静态变量的加载要早于对象的创建。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
类变量 | 实例变量 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
3.3 静态属性举例:System.out; Math.PI;
4.使用static修饰方法:静态方法
① 随着类的加载而加载,可以通过”类.静态方法”的方式进行调用
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "姚明";
c1.age = 40;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "马龙";
c2.age = 30;
c2.nation = "CHINA";
System.out.println(c1.nation);
//编译不通过
// Chinese.name = "张继科";
c1.eat();
Chinese.show();//show是static方法
//编译不通过,类不能调用非静态方法
// Chinese.eat();
// Chinese.info();
}
}
//中国人
class Chinese{
String name;
int age;
static String nation;
//非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
public void eat(){
System.out.println("中国人吃中餐");
//调用非静态结构
this.info();
System.out.println("name :" +name);
//调用静态结构
walk();
System.out.println("nation : " + nation);
}
//静态方法中,只能调用静态的方法或属性
//在静态的方法内,不能使用this关键字、super关键字
public static void show(){
System.out.println("我是一个中国人!");
//不能调用非静态的结构,this.eat()也是错误的
// eat();
// name = "Tom";
//可以调用静态的结构
System.out.println(Chinese.nation);
walk();
}
public void info(){
System.out.println("name :" + name +",age : " + age);
}
public static void walk(){
}
}
②
静态方法 | 非静态方法 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
③ 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
5. static注意点:
5.1 在静态的方法内,不能使用this关键字、super关键字
5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
6. 开发中,如何确定一个属性是否要声明为static的?
> 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
> 类中的常量也常常声明为static
开发中,如何确定一个方法是否要声明为static的?
> 操作静态属性的方法,通常设置为static的(get,set方法)
> 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections
final:最终的
final可以用来修饰的结构:类、方法、变量
2. final 用来修饰一个类:此类不能被其他类所继承。比如:String类、System类、StringBuffer类
3. final 用来修饰方法:表明此方法不可以被重写。比如:Object类中getClass();
4. final 用来修饰变量:此时的”变量”就称为是一个常量
4.1 final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
4.2 final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值 以后,就只能在方法体内使用此形参,但不能进行重新赋值。//【面试题】排错:
//题目一
public class Something {
public int addOne(final int x) {
return ++x; // return x + 1;
}//有錯,x不可以重新复制
}
//题目二,无错误,o不能更改,但是可以调用
public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o);
}
public void addOne(final Other o) {
// o = new Other();
o.i++;
}
}
class Other {
public int i;
}
abstract
```java package com.atguigu.java; /*
- abstract关键字的使用
- 1.abstract:抽象的
- 2.abstract可以用来修饰的结构:类、方法
- abstract修饰类:抽象类
此类不能实例化
抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
- abstract修饰方法:抽象方法
抽象方法只有方法的声明,没有方法体
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰 */ public class AbstractTest { public static void main(String[] args) {
//一旦Person类抽象了,就不可实例化 // Person p1 = new Person(); // p1.eat();
} }
//包含抽象方法的类,一定是一个抽象类 abstract class Creature{ public abstract void breath(); }
abstract class Person extends Creature{ String name; int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法:
// public void eat(){
//
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
//父类抽象方法需要重写
public void eat(){
System.out.println("学生多吃有营养的食物");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的没有雾霾的空气");
}
}
/*
- abstract使用上的注意点:
- 1.abstract不能用来修饰:属性、构造器等结构 //abstract需要被重写,而构造器只能重载
- 2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类
-
问题
问题1:为什么抽象类不可以使用final关键字声明?不可以
问题2:一个抽象类中可以定义构造器吗?可以
问题3:是否可以这样理解:抽象类就是比普通类多定义了抽象方法,除了不能直接进行类的实例化操作之外,并没有任何的不同练习
```java public abstract class Employee{ public string name; public int id; public double salary;
public abstract void work(); public Employee(string n,int m,double s){
name=n;
id=m;
salary=s;
} }
public class Manager extend Employee{ public double bonus; Employee emp = new Employee(‘zhuang’,101,12378);
}
public class CommonEmployee extend Employee{