我的原创地址:https://thorthegod.github.io/
Java后端特殊细节
1.java中的实例变量:
含义:
实例变量:定义在类中但在任何方法之外。(New出来的均有初始化)
与局部变量的异同:
(局部变量:定义在方法之中的变量)
-
局部变量要先赋值,再进行运算,而实例变量均已经赋初值。
-
实例变量的对象赋初值为null。
-
局部变量不允许范围内定义两个同名变量。实例变量的作用域在本类中完全有效,当被其他的类调用的时候也可能有效。
-
实例变量和局部变量都允许命名冲突。
代码实例:
public class Sample
{
private int a=1; //实例变量
public void b()
{
int a=2; //局部变量
System.out.println("局部变量:a="+a);
System.out.println("实例变量:a="+this.a);//局部变量的作用域内引用实例变量方法:this.变量名
}
public static void main(String[] args)
{
new Sample().b();
}
}
2.构造器:
-
构造器就是和类名相同但无返回类型的方法。创建构造器就是构建特定方法。而构造器最大的用处就是在创建对象时执行初始化。每当创建一个对象时,系统会为这个对象的实例进行默认的初始化。如果想改变这种默认的初始化,就可以通过自定义构造器来实现。
比如
{
public A()
{
}
}
//其中A方法 就是class A的构造器 虽然构造器没有返回值但可以有参数如
class A
{
public A(String a,String b)
{
}
}
一个类也可以有多个构造器如
class A
{
public A()
{
}
public A(String a,String b)
{
}
}
当你new A()时,无参那个构造器被调用,当你new A(“ddd”,“fff”)时,那个有参的构造器被调用,如果你没有写构造器则jvm会调用一个默认的无参的构造器(故调用父类默认构造器的条件:子类没有声明任何构造器;编译器为子类加的缺省构造器一定为无参数的构造器;父类一定要存在一个无参数的构造器)。
PS:构造器在类初始化的时候被调用通常被用来做一些初始化的工作。
-
构造器与方法的具体差异:
1. 功能和作用的不同 构造器是为了创建一个类的实例。用来创建一个对象,同时可以给属性做初始化。这个过程也可以在创建一个对象的时候用到:Platypus p1
= new Platypus(); 相反,方法的作用仅仅是功能函数,执行java代码。2. 修饰符,返回值和命名的不同
和方法一样,构造器可以有任何访问的修饰: public, protected, private或者没有修饰.
不同于方法的是,构造器不能有以下非访问性质的修饰: abstract, final, native, static, 或者
synchronized。3. 返回类型
方法必须要有返回值,能返回任何类型的值或者空返回值(void),构造器没有返回值,也不需要void。
4. 命名
构造器使用和类相同的名字,而方法则不同。按照习惯,方法通常用小写字母开始,而构造器通常用大写字母开始。
构造器通常是一个名词,因为它和类名相同;而方法通常更接近动词,因为它说明一个操作。
5. 调用
构造:只有在对象创建的时候才会去调用,而且只会调用一次。
方法:在对象创建之后才可以调用,并且可以调用多次。
6. "this"的用法
方法引用this指向正在执行方法的类的实例。静态方法不能使用this关键字,因为静态方法不属于类的实例,所以this也就没有什么东西去指向。构造器的this指向同一个类中,不同参数列表的另外一个构造器。下面的代码:
public class Platypus { String name; Platypus(String input) { name = input; } Platypus() { this("John/Mary Doe"); } public static void main(String args[]) { Platypus p1 = new Platypus("digger"); Platypus p2 = new Platypus(); } }
在代码中,有2个不同参数列表的构造器。第一个构造器,给类的成员name赋值,第二个构造器,调用第一个构造器,给成员变量name一个初始值
“John/Mary Doe”.在构造器中,如果要使用关键字this,那么必须放在第一行,如果不这样将导致一个编译错误。
7. 继承构造器是不能被继承的。子类可以继承超类的任何方法。
做后端时遇到的细节:
-
@的用法
语法: @关键字(值)
@用于把关键字和值传递给编译器,更精确低控制编译器的动作。
关键字都是随技术、框架、编译器的不同而不同,含义也不同、数量不定。可以由子技术或开发者扩充。
比如:@override
说明将重写下个出现的方法。
@WebServlet( name="Hello", urlPatterns={"/hello.view"}, loadOnStartup=1 ) public class HelloServlet extends HttpServlet {
上面的@WebServlet告知容器,HelloServlet这个Servlet的名称是Hello,这是由name属性指定的;而如果客户端请求的URL是/hello.view,则由具Hello名称的Servlet来处理,这是urlPatterns属性来指定的。在Java EE相关应用程序中使用标注@时,可以注意到,我们没有设置的属性通常会有默认值。例如,若没有设置@WebServlet的name属性,默认值会是Servlet的类完整名称。
另外,@标注不是语句,不应加入;结束分号。而且也要导入相关:
import javax.servlet.annotation.WebServlet;
-
request的getRequestDispatcher()方法能实现两种跳转:
(1)跳转到一个servlet
request.getRequestDispatcher("跳转的servlet名").forward(request, response);
(2)跳转到一个页面
request.getRequestDispatcher("文件路径").forward(request, response);
同时,forward方法成功后可以将request和response传递该下一个jsp 、servlet、html等(但不能够连续传递),从而可以实现在下一个界面再次得到第一次获得的request信息并处理等操作。
-
servlet的严格
servlet格式要求非常高。每一个servlet类,都需要有一个servlet集和servlet-mapping集,且二者name对应。其中servlet集还有servlet–class编译文件名,mapping中的url必须要有/起头,表示调用到这个servlet时要转到的地址为 上下文/xxx。倘若格式出错,极有可能导致tomcat异常,如启动后无法打开localhost等。
代码示例:<servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping>
-
html与sevlet的交互
原理:html(或jsp)使用servlet的方法是在表单中的action属性填入去掉/的url地址。触发提交表单动作action时,浏览器会自动在原地址后添加/xxx并转入该地址页面,同时寻找该url对应的servlet并执行相应javaclass编译文件。
代码示例:<form action="login" method="post"> 管理员名:<input type="text" name="username"> 密码: <input type="password" name="userpwd"> <input type="submit" value="登录"> </form>
可以看到,action中的值 login 对应servlet的url地址。如此可以实现前端——>servlet——>后端的通路。
-
前后端乱码问题
由于浏览器,控制台和IDE对字符的转码格式不一定相同,当需要接受或传送字符时,我们需要设置相应的request和response属性,且这种设置要早于其他调用,如要在response.getWriter方法前设置好转码格式,从而避免乱码。
目前我在用的好用的调整转码格式代码:request.setCharacterEncoding("utf8"); response.setContentType("text/html;charset=utf-8");
-
JDBC连接数据库的步骤:
-
加载数据库驱动到JVM(JAVA VIRTUAL MACHINE)
try{ //加载MySql的驱动类 Class.forName("com.mysql.cj.jdbc.Driver");//核心语句 }catch(ClassNotFoundException e){ System.out.println("找不到驱动程序类 ,加载驱动失败!"); e.printStackTrace() ; }
注意:
com.mysql.jdbc.Driver 是 mysql-connector-java 5中的,
com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6中的。请根据版本自行选择匹配的Driver。成功加载后,Driver类的实例会被注册到DriverManager类中。
-
提供具体数据库的URL(路径),数据库用户名和密码
书写形式:协议:子协议:数据源标识
协议:在JDBC中总是以jdbc开始
子协议:是桥连接的驱动程序或是数据库管理系统名称。
数据源标识:标记找到数据库来源的地址与连接端口。
例如:(MySql的连接URL)//可以有这么长! jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=gbk;
这段url表示以本地3306端口连接mysql中的test数据库(假设mysql中已经创建test数据库)。
其后还可以添加:
useUnicode=true //表示使用Unicode字符集。 characterEncoding=gbk //字符编码方式。 serverTimezone=GMT%2B8 //设置时区。可以用于解决时区报错 //简单项目用下面这钟就完事了 jdbc:mysql://localhost:3306/test;
注意:
如果java报错:The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more than one time zone,就应该将时区设置加入url中,或者在命令行直接改变所用数据库的时区等,以mysql为例详见https://www.jb51.net/article/84198.htm
-
将第二步的信息传递给JDBC创建连接
要连接数据库,首先需要向java.sql.DriverManager请求并获得Connection对象,该对象代表一个数据库的连接。
使用这个DriverManager.getConnection(String url,String username,String password);
方法传入指定的欲连接的数据库的路径、数据库的用户名和
密码来获得。
例如://连接MySql的test数据库,用户名是root,密码为123456 String url = "jdbc:mysql://localhost:3306/test" ; String username = "root" ; String password = "123456" ; try{ Connection conn = DriverManager.getConnection(url, username, password); }catch(SQLException e){ System.out.println("数据库连接失败!"); e.printStackTrace() ; }
-
创建Statement从而能够在java中执行SQL语句
要执行SQL语句,必须获得第三步创建的conn中的java.sql.Statement实例。Statement实例分以下3种类型:
1、执行静态SQL语句。通过Statement实例实现。
2、执行动态SQL语句。通过PreparedStatement实例实现(常用)。
3、执行数据库存储过程。通过CallableStatement实例实现。
具体的实现方式:Statement stmt = conn.createStatement(); PreparedStatement prst = conn.prepareStatement(sql); CallableStatement cstmt =conn.prepareCall("{CALL demoSp(? , ?)}"); //根据需要选择其中一种类型
此外,可以给prst的数据封编号以后续使用
prst.setString(1, username); prst.setString(2, passwd);
-
执行SQL语句
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute
1、ResultSet executeQuery(String sqlString);:执行查询数据库的SQL语句。返回一个结果集(ResultSet)对象。
2、int executeUpdate(String sqlString);:用于执行INSERT、UPDATE或DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等。
3、execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的 语句。
具体实现的代码:ResultSet rs = prst.executeQuery("SELECT * FROM ?"); int rows = prst.executeUpdate("INSERT INTO ?"); boolean flag = prst.execute(String sql);
-
处理结果
两种情况:
1、执行更新,返回的是本次操作影响到的记录数。
2、执行查询,返回的结果是一个ResultSet对象。
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。
使用结果集(ResultSet)对象的访问方法获取数据:while(rs.next()){ //rs.next()有true和false两个返回值 String name = rs.getString("name") ; String pass = rs.getString(1) ; // 此方法比较高效 } 注意:列是从左到右编号的,并且从列1开始
-
关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全部关闭,以释放JDBC资源,关闭顺序和声明顺序相反,后声明先关闭(类似栈)。顺序:
1、关闭记录集
2、关闭声明
3、关闭连接对象if(rs!= null){ // 关闭记录集 try{ rs.close() ; }catch(SQLException e){ e.printStackTrace() ; } } if(prst!= null){ // 关闭声明 try{ prst.close() ; }catch(SQLException e){ e.printStackTrace() ; } } if(conn!= null){ // 关闭连接对象 try{ conn.close() ; }catch(SQLException e){ e.printStackTrace() ; } }
感谢:第六节JDBC连接逻辑大部分参考http://www.cnblogs.com/hongten/archive/2011/03/29/1998311.html。
在此鸣谢!
-