一、包
1.1 包的作用是什么?
-
按照不同的主题分类管理我们的类 => 此时你可以把包当成文件夹的概念,不同文件夹放不同主题的类
-
避免类的重名 => 包相当于类的前缀,类的全名称是 包.类名,例如:java.util.Scanner, java.lang.String, java.lang.Math, java.lang.System
-
结合权限修饰符,限定某些类或成员的可见性范围
one包的类
package one;
//注意:这里的类前面 故意 没有加 public
class DemoOne {
public static void m(){
System.out.println("静态方法m");
}
}
two包的测试类
package two;
import one.DemoOne;
public class TestDemoOne {
public static void main(String[] args) {
DemoOne d = new DemoOne();
DemoOne.m();
}
}
//以上代码会报错
1.2 如何声明包?
1、在源代码中的package语句
package 包名;
这句语句必须在源文件的首行。我们不会手动写这句话,而且由IDEA自动加这句话。
包名的命名规范:
-
所有单词都小写,单词直接使用 . 分割,每一个.代表一个层级。
-
习惯上用公司域名倒置 + 主题名 来命名,例如: com.atguigu.xxx
-
一级域名:com商业性的公司, org非盈利性组织,edu教育机构等
-
2、通过IDEA怎么创建包
3、在包下面如何创建类
1.3 如何跨包使用类
前提:这个类必须是跨包可以用的,即public。
方式一:使用全名称
方式二:import 包名.类名; 然后代码中使用类的简名称
Java中规定使用java.lang包下的类,不需要import语句,就可以直接使用简名称。
导包语句的写法:
import 包名.类名;
import 包名.*;
com.atguigu.bean包的其他类
package com.atguigu.bean;
public class Student {
}
package com.atguigu.bean;
public class Teacher {
}
package com.atguigu.bean;
public class Employee {
}
package com.atguigu.bean;
public class TestStudent {
public static void main(String[] args) {
Student s = new Student();//使用同一个包的类不需要导包
}
}
com.atguigu.pck包的测试类
package com.atguigu.pck;
/*import com.atguigu.bean.Employee;
import com.atguigu.bean.Student;
import com.atguigu.bean.Teacher;*/
import com.atguigu.bean.*;
import java.util.Scanner;
/*import java.lang.String;
import java.lang.System;*/
public class TestImport {
public static void main(String[] args) {
//java.util.Scanner input = new java.util.Scanner(System.in);//使用类的全名称
Scanner input = new Scanner(System.in);
input.close();
//使用com.atguigu.bean包下的Student类
Student s = new Student();
Teacher t = new Teacher();
Employee e = new Employee();
}
}
1.4 静态导入(了解)
package com.atguigu.pck;
import static java.lang.Math.*;
public class TestStaticImport {
public static void main(String[] args) {
//调用Math类的一些静态方法,静态常量
/* System.out.println(Math.PI);//圆周率
System.out.println(Math.random());//随机产生[0,1)的小数
System.out.println(Math.sqrt(9));//求平方根
System.out.println(Math.max(5,6));//求最大值
System.out.println(Math.pow(5,6));//求5的6次方*/
System.out.println("======================");
System.out.println(PI);//圆周率
System.out.println(random());//随机产生[0,1)的小数
System.out.println(sqrt(9));//求平方根
System.out.println(max(5,6));//求最大值
System.out.println(pow(5,6));//求5的6次方
}
}
二、类的第三个成员:构造器(非常重要)
2.1 构造器的作用
-
构造器与关键字new一起,用来创建对象。换句话说,new关键字后面的就是构造器。
-
在new对象时,要为对象的属性初始化。如果没有指定值,属性就是默认值。
2.2 构造器的特点
(1)每一个类都有构造器
(2)如果这个类没有==“手动”==编写任何构造器的话,那么编译器就会==“自动”==给你这个类添加默认的无参构造
。
但是,如果你==“手动”编写==了任何构造器,那么编译器就==不会再“自动”==给你加无参构造了,如果需要无参构造,就必须自己==手动添加==。
(3)构造器也可以手动编写,并且可以重载。
(4)构造器的名称必须与类名完全一致,包括大小写。
(5)构造器没有返回值类型。不能写返回值类型(void等)
(6)构造器的修饰符只能是public、protected、缺省、private,不能有其他修饰符,例如:static,final等
构造器的语法格式:
【修饰符】 构造器名称(【形参列表】){
【构造器的方法体;】
}
//一共4个部分,没有返回值类型
注意:构造器与普通方法非常相似,不同的是,构造器没有返回值类型。很多程序员,会把构造器称为构造方法,但是笔记中,一般叫构造器,避免初学者搞混淆。
2.3 构造器示例代码
package com.atguigu.constructor;
public class Rectangle {//矩形
//成员变量,属性,实例变量
public double length;
public double width;
public Rectangle(double chang, double kuan){//手动写的有参构造
length = chang;
width = kuan;
}
public Rectangle(){//手动写的无参构造
}
public String getInfo(){
return "长:" + length +",宽:" + width;
}
}
package com.atguigu.constructor;
public class TestRectangle {
public static void main(String[] args) {
//调用无参构造创建了Rectangle类的对象
Rectangle r1 = new Rectangle();
//调用有参构造创建了Rectangle类的对象
Rectangle r2 = new Rectangle(8, 5);
//调用r1和r2对象的getInfo方法
System.out.println(r1.getInfo());//长:0.0,宽:0.0
System.out.println(r2.getInfo());//长:8.0,宽:5.0
}
}
2.4 构造器的快捷键
2.5 关键字this
1、this.属性
2、this() 或 this(实参列表)
this() 或 this(实参列表):都必须在构造器的首行。
-
this():调用本类的无参构造
-
this(实参列表):调用本类的有参构造,至于调用哪个有参构造,要看参数列表的匹配情况
package com.atguigu.constructor;
public class Employee {
//属性
public String name;
public String tel;
public double salary;
public int age;
public String address;
//用快捷键生成构造器,Alt + Insert ,部分同学的键盘模式需要同时按Fn
//在类的里面,不要在类的外面按快捷键,也不要在方法体里面按快捷键
public Employee() {
}
public Employee(String name, String tel, double salary, int age, String address) {
/*this.name = name;
this.tel = tel;
this.salary = salary;*/
this(name,tel,salary);
this.age = age;
this.address = address;
// this(name,tel,salary);//错误,必须在构造器首行
}
public Employee(String name, String tel, double salary) {
// this();//这类写它没有意义,去掉它
this.name = name;
this.tel = tel;
this.salary = salary;
}
}
package com.atguigu.constructor;
public class TestEmployee {
public static void main(String[] args) {
//分别用3种方式,创建对象
Employee e1 = new Employee();
Employee e2 = new Employee("张三","10086",15000);
//快捷键,查看调用的构造器或方法的形参列表,在()里面按Ctrl + P
Employee e3 = new Employee("李四","10010",16000,25,"上海");
// Employee e4 = new Employee("王五",17800);//报错
//如果要看到对象的信息,必须自己再加打印语句
}
}
三、封装
3.1 什么是封装?
封装是面向对象的基本特征之一。
生活中,大家收发快递,都有包裹。想一想快递为什么要用包裹?
-
避免损坏 => 为了安全
-
保护隐私 => 为了信息安全
-
便于运输 => Java中便于使用
类中的封装:
-
为了安全,可以让外界按照我指定的方式(通常就是get/set等方法)来操作属性。例如:通常会将属性进行私有化。
-
为了方便使用,可以将重复性的代码封装为方法,实现重复使用的效果。一个方法封装了一个功能。
package com.atguigu.encapsolation;
public class Student {
//属性
//public:公共的,随意可见的
//private:私有的,只有本类可以“直接”使用
private String name;
private int score;//成绩属性
// public int grade;//故意对比,写了两个成绩属性
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getScore(){
return score;
}
public void setScore(int score){
if(score>=0 && score<=100) {
this.score = score;
}else{
System.out.println("成绩必须在[0,100]之间");
}
}
}
package com.atguigu.encapsolation;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student();
/*s1.name = "张三";
s1.score = 89;*/
//报错,name和score是pirvate私有的属性,在测试类中不能直接操作它
s1.setName("张三");
System.out.println("姓名:" + s1.getName());
s1.setScore(89);
System.out.println("成绩:" + s1.getScore());
/* int chengJI = -10;
if(chengJI>=0 && chengJI<=100) {
s1.grade = chengJI;
}
Student s2 = new Student();
int chengJI2 = -10;
if(chengJI2>=0 && chengJI2<=100) {
s2.grade = chengJI2;
}*/
}
}
3.2 属性私有化
1、属性前面用private修饰
【修饰符】 class 类名{
private 数据类型 属性名1;
private 数据类型 属性名2;
private 数据类型 属性名3;
}
2、会为属性提供get/set
-
get方法:当我们调用get方法时,可以==得到==一个值。
-
set方法:当我们调用set方法时,可以==修改==一个属性的值。
-
get/set方法是有快捷键自动生成:Alt + Insert
-
boolean类型的get方法的开头单词从get换成了is
-
静态变量的get/set方法也是静态的,而且在静态方法中,局部变量(这里是形参)与静态变量重名,需要加“类名.静态变量”进行区分。
-
实例变量的get/set方法也是非静态的,在非静态方法中,局部变量(这里是形参)与实例变量重名,需要加“this.实例变量”进行区分。
-
【修饰符】 class 类名{
private 数据类型1 属性名1;
private 数据类型 属性名2;
private 数据类型 属性名3;
//为属性1 提供了 一对get/set方法
public 数据类型1 get属性名1(){
return 属性名1;
}
public void set属性名1(数据类型1 形参名1){
this.属性名1 = 形参名1;
}
//为属性2 提供了 一对get/set方法
public 数据类型2 get属性名2(){
return 属性名2;
}
public void set属性名2(数据类型2 形参名2){
this.属性名2 = 形参名2;
}
//为属性3 提供了 一对get/set方法
public 数据类型3 get属性名3(){
return 属性名3;
}
public void set属性名3(数据类型3 形参名3){
this.属性名3 = 形参名3;
}
/*
//一般很少用下面这个set方法,同时为3个属性赋值,这就表示一旦修改,需要同时修改3个属性。复用性比较差。
public void setInfo(数据类型1 形参名1, 数据类型2 形参名2, 数据类型3 形参名3){
this.属性名1 = 形参名1;
this.属性名2 = 形参名2;
this.属性名3 = 形参名3;
}*/
}
3、get/set与构造器的区别
-
构造器:用来创建对象的,可以在创建对象的同时给实例变量初始化
-
get/set:在对象创建之后,用来获取/修改单个属性的值
4、示例代码
package com.atguigu.encapsolation;
public class Employee {
//属性,私有化了,public -> private
private String name;
private String tel;
private double salary;
private int age;
private String address;
private boolean marry;//是否已婚
private static String company;//公司名 静态变量
//构造器 快捷键 Alt + Insert
public Employee() {
}
public Employee(String name, String tel, double salary, int age, String address, boolean marry) {
this.name = name;
this.tel = tel;
this.salary = salary;
this.age = age;
this.address = address;
this.marry = marry;
}
//方法
//get/set 快捷键 Alt + Insert
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
//对于boolean类型的属性,get方法的开头单词从get换成is
public boolean isMarry() {
return marry;
}
public void setMarry(boolean marry) {
this.marry = marry;
//当局部变量(这里是形参)与实例变量重名了,需要在非静态方法或构造器中使用 “this.实例变量”进行区别
}
public static String getCompany() {
return company;
}
public static void setCompany(String company) {
Employee.company = company;
//当局部变量(这里是形参)与静态变量重名了,需要在静态方法中使用 “类名.静态变量”进行区别
}
public String getInfo(){
return "姓名:" + name +",电话:" + tel
+",薪资:" + salary +",年龄:" + age +",地址:" + address
+",是否已婚:" + (marry?"是":"否")
+",公司名:" + company;
}
}
package com.atguigu.encapsolation;
public class TestEmployee {
public static void main(String[] args) {
Employee.setCompany("尚硅谷");
Employee e = new Employee("张三","10086",18000,23,"北京",true);
System.out.println(e.getInfo());
//如果对象已经创建好的情况下,要单独修改某个属性值,就要调用它的set方法
//例如给e对象涨薪20%
e.setSalary(e.getSalary() * 1.2);
//如果想要单独获取某个属性值,调用它对应get方法
System.out.println("e对象目前的薪资:" + e.getSalary());
}
}
3.3 权限修饰符
1、可见性范围
权限修饰符,又称为访问控制修饰符。用于限定类或成员的可见性范围。下面这张表格说明了几种权限修饰符的可见性范围:
本类 | 同一个包的其他类中 | 其他包的子类中 | 其他包的非子类中 | |
---|---|---|---|---|
private | √ | × | × | × |
缺省(不写) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
2、示例代码
com.atguigu.first包的类
package com.atguigu.first;
public class Father {
private int a;//private,私有的
int b; //不写权限修饰符,称为缺省,默认的
protected int c; //protected,受保护的
public int d; //public,公共的
public void m(){
//在本类中,只要不违反静态不能访问非静态的原则,本类的所有成员,无论哪种权限修饰符,都是可以直接使用的。
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("d = " + d);
}
}
package com.atguigu.first;
public class TestFather {
public static void main(String[] args) {
Father father = new Father();
// System.out.println("father.a = " + father.a);//错误,私有的不能跨类使用
System.out.println("father.b = " + father.b);
System.out.println("father.c = " + father.c);
System.out.println("father.d = " + father.d);
}
}
com.atguigu.second包的类
package com.atguigu.second;
import com.atguigu.first.Father;
//Son类现在是Father类的子类
public class Son extends Father {
public void fun(){
// System.out.println("a = " + a);//错误的,私有的不允许跨类
// System.out.println("b = " + b);//错误的,缺省的不允许跨包
System.out.println("c = " + c);//可以,受保护的,只要是在本子类中就可以访问所有父类的protected成员
System.out.println("d = " + d);
}
}
package com.atguigu.second;
import com.atguigu.first.Father;
public class TestFatherInOtherPackage {
public static void main(String[] args) {
Father father = new Father();
// System.out.println("father.a = " + father.a);//错误,私有的不能跨类使用
// System.out.println("father.b = " + father.b);//错误,缺省不能跨包使用
// System.out.println("father.c = " + father.c);//错误,受保护如果跨包的话,必须是在子类中
System.out.println("father.d = " + father.d);
}
}
3、权限修饰符分别可以修饰什么
-
class前面可以出现的权限符是:public 或 缺省不写
-
成员(成员变量、成员方法、构造器)前面:四种都可以加
-
局部变量:啥都不可以加(四种权限修饰符都不可以,static也不可以),除了final
package com.atguigu.encapsolation;
public class Demo {//公共的类
//属性的前面,四种权限修饰符都可以
private int a;
int b;
protected int c;
public int d;
//构造器的前面,四种权限修饰符都可以
// public Demo(){}
// Demo(){}
// protected Demo(){}
private Demo(){}
//方法的前面,四种权限修饰符都可以
public void m1(){
}
void m2(){
}
protected void m3(){
}
private void m4(){
}
}
/*
class Demo {//类的权限修饰符是缺省
}*/
/*private class Demo {//类的权限修饰符是私有的,错误的
}*/
/*
protected class Demo {//类的权限修饰符是受保护的,错误的
}*/
package com.atguigu.encapsolation;
public class TestVariable {
static int a;//静态变量
int b;//实例变量
public void method(int d){//形参也是局部变量
int c;//局部变量,前面不可以加static,pubilc,protected,private等
}
}
3.4 标准Javabean
bean:豆子
Javabean:Java豆,因为Java的名称来源于 产咖啡的爪哇岛,所以Java类也被称为Java豆,咖啡豆。
这里讲的标准Javabean是指一种写Java类的规范:
-
属性私有化
-
提供get/set方法
-
提供无参构造
-
可以有选择添加有参构造(自选)
-
重写toString等(明天讲)
package com.atguigu.version3;
public class Teacher {
private String name;
private double salary;
public Teacher() {
}
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
3.5 练习题
练习题1
(1)定义矩形类Rectangle,
-
声明实例变量长和宽,全部私有化private,
-
提供相应的get/set方法,如果set方法的参数值<=0,则提示矩形的长和宽必须是正数
-
声明public double area(),返回矩形面积
-
声明public double perimeter():返回矩形的周长
-
声明public String getInfo():返回矩形的长、宽、面积、周长信息
(2)测试类的main中创建一个可以装3个矩形对象的数组,并调用set方法为对象的属性赋值,依次长是8,7,6,宽是2,3,4
-
遍历输出矩形对象数组
-
按照矩形对象的length属性值从小到大排序后,遍历输出矩形对象数组
-
按照矩形对象的面积从小到大排序后,遍历输出矩形对象数组
矩形类
package com.atguigu.exer3;
public class Rectangle {
private double length;
private double width;
public Rectangle() {
}
public Rectangle(double length, double width) {
if(length <= 0 || width <= 0){
System.out.println("矩形的长和宽必须是正数");
return;
}
this.length = length;
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
if(length <= 0){
System.out.println("矩形的长必须是正数");
return;
}
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
if(width <= 0){
System.out.println("矩形的宽必须是正数");
return;
}
this.width = width;
}
public double area(){
return length * width;
}
public double perimeter(){
return 2 * (length + width);
}
public String getInfo() {
return "长:" + length + ",宽:" + width + ",面积:" + area() +",周长:" + perimeter();
}
}
矩形测试类
package com.atguigu.exer3;
public class TestRectangle {
public static void main(String[] args) {
Rectangle[] arr = new Rectangle[3];
arr[0] = new Rectangle();//调用无参构造创建矩形对象
arr[0].setLength(8);//调用set方法为 属性赋值
arr[0].setWidth(2);//调用set方法为 属性赋值
arr[1] = new Rectangle(7,3);//调用有参构造创建矩形对象
arr[2] = new Rectangle(6,4);//调用有参构造创建矩形对象
System.out.println("原始数据:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i].getInfo());
}
System.out.println("按照length从小到大排序:");
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length - i; j++) {
if (arr[j].getLength() > arr[j + 1].getLength()) {
Rectangle temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i].getInfo());
}
System.out.println("按照面积从小到大排序:");
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length - i; j++) {
if (arr[j].area() > arr[j + 1].area()) {
Rectangle temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i].getInfo());
}
}
}
练习题2
(1)定义三角形类Triangle,
-
声明实例变量a,b,c,代表三角形三条边,全部私有化private,
-
提供每条边的get方法,
-
提供public void setBases(double a, double b, double c):要求参数a,b,c的值必须大于等于0,且满足三角形三边关系要求(即任意两边之后大于第三边),否则提示错误信息
-
声明public double area(),返回三角形面积
-
声明public double perimeter():返回三角形周长
-
声明public String getInfo():返回三角形的三条边,面积和周长
(2)测试类的main中创建一个三角形对象,并调用相应方法
三角形类
package com.atguigu.exer4;
public class Triangle {
private double a;
private double b;
private double c;
public Triangle() {
}
public Triangle(double a, double b, double c) {
/*this.a = a;
this.b = b;
this.c = c;*/
setBase(a,b,c);
}
public double getA() {
return a;
}
public double getB() {
return b;
}
public double getC() {
return c;
}
public void setBase(double a, double b, double c){
if(a>0 && b>0 && c>0 && a+b>c && b+c>a && a+c>b){
this.a = a;
this.b = b;
this.c = c;
}else{
System.out.println("三角形的三边必须是正数,且任意两边之和大于第三边");
// throw new IllegalArgumentException(a+","+b+","+c +"不符合三角形要求");
}
}
/*public void setBase(double a, double b, double c){
if(a<=0 || b<=0 || c<=0 || a+b<=c || b+c<=a || a+c<=b){
System.out.println("三角形的三边必须是正数,且任意两边之和大于第三边");
return;//提前结束方法的执行
}
this.a = a;
this.b = b;
this.c = c;
}*/
public double area(){
double p = (a+b+c)/2;
return Math.sqrt(p*(p-a)*(p-b)*(p-c));
//海伦公式
}
public double perimeter(){
return a + b+c;
}
public String getInfo(){
return "a:" + a + ",b:" + b + ",c=" +c +",面积:" + area() +",周长:" + perimeter();
}
}
三角形的测试类
package com.atguigu.exer4;
public class TestTriangle {
public static void main(String[] args) {
Triangle t = new Triangle();
t.setBase(3,4,5);
System.out.println(t.getInfo());
System.out.println("===================");
Triangle t2 = new Triangle(1,2,5);
System.out.println(t2.getInfo());
}
}