Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

java interface

648  1 2 все
Kvint постоялец05.07.17 22:27
Kvint
05.07.17 22:27 

Привет всем.

у меня такой вопрос.

есть интерфейс:


public interface TestInterface {}


есть два класса, которые его имплементируют:


public class A implements TestInterface{
public A(BigInteger value){
System.out.println("This is A");
}
}

public class B implements TestInterface{
public B(BigDecimal value){
System.out.println("This is B");
}
}


Нужно что бы в зависимости от параметра (тут BigInteger и BigDecimal) создавался конкретный объект.

Что то типа TestInterface ti = new TestInterface(BigInteger bi){}

Это возможно сделать? если да то как?


#1 
GANDJUBAS Ганджубас05.07.17 22:54
GANDJUBAS
NEW 05.07.17 22:54 
в ответ Kvint 05.07.17 22:27

Я не знаю, на сколько могут отличаться классы А от В, но чисто по описанию я бы реализовал через Generic.


http://www.quizful.net/post/java-generics-tutorial

#2 
Murr патриот05.07.17 23:57
Murr
NEW 05.07.17 23:57 
в ответ Kvint 05.07.17 22:27

Что то типа TestInterface ti = new TestInterface(BigInteger bi){}

-----

Гы... инстанцировать объект класса интерфейс? Может почитать что-то по Жабе?


Это возможно сделать? если да то как?

-----

Читать - паттерны. Паттерн Фабрика классов.

#3 
Kvint постоялец06.07.17 06:54
Kvint
NEW 06.07.17 06:54 
в ответ GANDJUBAS 05.07.17 22:54

думаю generic не совсем подойдёт в данном случае. Сейчас посмотрю фабрику классов, как советует мур. Ещё есть идея использовать serviceloader.

#4 
MrSanders старожил06.07.17 10:37
NEW 06.07.17 10:37 
в ответ Kvint 06.07.17 06:54

Не надо serviceloader. Фабрика правильное решение. Только аккуратнее, не забывайте что ява язык с "одиночной диспетчеризацией" (single dispatch).

#5 
BorisL0 знакомое лицо06.07.17 12:21
NEW 06.07.17 12:21 
в ответ Kvint 05.07.17 22:27

А так не пойдет?

TestInterface ti = (Ваше условие) ? (new A(value)) : (new B(value));

#6 
Kvint постоялец06.07.17 22:48
Kvint
NEW 06.07.17 22:48 
в ответ BorisL0 06.07.17 12:21

кстати тоже хороший способ. Но у меня будет не только A и B. У меня будет A,B,C,D,E классы.

А вообще мне идея с интерфейсом не очень нравится, тк все классы имеют свои методы, которые в других классах не существуют. Но это идея бетроера. Завтра буду говорить с ним по этому поводу

#7 
AlexNek патриот07.07.17 01:42
AlexNek
NEW 07.07.17 01:42 
в ответ Kvint 06.07.17 06:54

фабоика для "постоянного количества" классов. Сервис лоадер для переменного заранее неизвестного.

Незнаю есть ли в Яве атрибуты для классов, но туда можно было кинуть "ид" для загрузки.

#8 
Kvint постоялец07.07.17 06:56
Kvint
NEW 07.07.17 06:56 
в ответ AlexNek 07.07.17 01:42

имеется ввиду dependency injections?

#9 
AlexNek патриот10.07.17 01:56
AlexNek
NEW 10.07.17 01:56 
в ответ Kvint 07.07.17 06:56

Не нашел как это будет в яве точно выглядеть, на шарпе это примерно так

[MyId(32)]
pulblic Class Test
{
...
}


#10 
Kvint постоялец10.07.17 16:44
Kvint
NEW 10.07.17 16:44 
в ответ AlexNek 10.07.17 01:56

Я поговорил сегодня с Бетроером. Он против dependency injection, говорит что это может повлиять на всю систему. И ему подходит вариант с factory. Но мне не нравится то, что интерфейс будет содержать все методы из всех классов. Например класс A должен будет реализовать методы, которые ему не нужны, а нужны классу B.

#11 
pavel-hh коренной житель10.07.17 17:00
pavel-hh
NEW 10.07.17 17:00 
в ответ Kvint 10.07.17 16:44

по-моему у вас с архитектурой приложения что-то не так, мягко говоря.

Linux is like a Wigwam. No Windows! No Gates! And Apache inside.
#12 
AlexNek патриот10.07.17 18:22
AlexNek
NEW 10.07.17 18:22 
в ответ Kvint 10.07.17 16:44

У Бетроера что очередная параноя на базе ДИ? хаха

https://msdn.microsoft.com/en-us/library/aa288059(v=vs.71)...

Как может номер "привязанный" к классу развалить систему и где он там ДИ увидел? В спецочках наверное.

Не, если очень постарться то можно всё сделать, но это надо сильно стараться спок


Но мне не нравится то, что интерфейс будет содержать все методы из всех классов

Нафига? Интерфес общий, а имплементации различные.

Если нужно в интерфейс выкидывать все методы, то необходимо срочно искать другого Бетроера.

#13 
Kvint постоялец10.07.17 18:47
Kvint
NEW 10.07.17 18:47 
в ответ AlexNek 10.07.17 18:22

ок. Я счас быстро uml накидаю и объясню как это по его мнению выглядеть должно. Я если честно уже не уверен, что мне делать

#14 
Kvint постоялец10.07.17 19:10
Kvint
NEW 10.07.17 19:10 
в ответ Kvint 10.07.17 18:47

#15 
Kvint постоялец10.07.17 19:16
Kvint
NEW 10.07.17 19:16 
в ответ Kvint 10.07.17 19:10

получается, что класс A и B содержат ненужные методы, тк эти методы в интерфейсе. Классам же на верху (SomethingA, SomethingB) нужны только определенные методы. Но эти классы должны знать только интерфейс.

Есть какое-то разумное решение у этой проблемы?

Ps uml набросал на коленке. Извиняюсь за качество

#16 
BorisL0 знакомое лицо10.07.17 20:42
NEW 10.07.17 20:42 
в ответ Kvint 10.07.17 19:10

А зачем методы doA и doB??? В интерфейсе пишете один метод, назовем его do, и в каждом классе реализации (A и B) своя реализация этого метода. Или я что-то не так понял?

#17 
Kvint постоялец10.07.17 20:53
Kvint
NEW 10.07.17 20:53 
в ответ BorisL0 10.07.17 20:42

методы могут быть разные с разными параметрами. Можно конечно попробовать generics, но это огромная работа, тк классов не два а пять и все делают разные вещи

#18 
BorisL0 знакомое лицо10.07.17 21:00
NEW 10.07.17 21:00 
в ответ Kvint 10.07.17 20:53

Тогда, как вариант: пишете еще одну архитектуру классов, т.е. интерфейс и реализации для "параметров", вроде IParameters, ParameterA, ParameterB,... Тогда в методе do для классов A,B,C,...будет один аргумент типа IParam, ну а каждая из реализаций будет использовать свою реализацию параметров ParameterA,...

#19 
AlexNek патриот10.07.17 21:47
AlexNek
NEW 10.07.17 21:47 
в ответ Kvint 10.07.17 18:47
Я если честно уже не уверен, что мне делать

Если не уверены, то нужно делать как шеф хочет, только чтобы было в письменной форме, без всяких вариантов - "а Вы меня не так поняли"


По идее он хочет абстрактную фабрику классов.

https://refactoring.guru/ru/design-patterns/abstract-facto...


https://en.wikipedia.org/wiki/Factory_method_pattern

http://www.oodesign.com/factory-method-pattern.html


методы могут быть разные с разными параметрами.

Понятно... архитектура от того же "Бетроера" смущ

Тогда самое простое, как уже написали: добавляем промежуточный класс/интерфейс для списка параметров. И его пользуем вместо списка различных параметров.

#20 
MrSanders старожил11.07.17 09:34
NEW 11.07.17 09:34 
в ответ Kvint 10.07.17 20:53

Было бы неплохо поконкретнее описать ваши А,Б, что делает doA, что - doB.

А то пока что под ваше описание подходит интерфейс, скажем List. doA это add(Object), doB это get(int), и реализации - ArrayList и LinkedList. SomethingA в список добавляет, SomethingB - читает. Всё разумно.

#21 
Kvint постоялец12.07.17 20:21
Kvint
NEW 12.07.17 20:21 
в ответ MrSanders 11.07.17 09:34

я могу выложить два этих класса, но они большие.

#22 
  joldosch местный житель12.07.17 21:50
joldosch
NEW 12.07.17 21:50 
в ответ Kvint 12.07.17 20:21

тебе нужно в методе интерфейса передать параметр класса Object, а в имплементации в каждом классе сделать фильтр на тип объекта...

#23 
Kvint постоялец14.07.17 11:03
Kvint
NEW 14.07.17 11:03 
в ответ joldosch 12.07.17 21:50

вы имеете ввиду скастовать нужный объект? тогда вся история с интерфейсом теряет свой смысл

#24 
Kvint постоялец14.07.17 11:08
Kvint
NEW 14.07.17 11:08 
в ответ Kvint 14.07.17 11:03

не могу выложить классы в читаемом формате.

#25 
BorisL0 знакомое лицо14.07.17 11:56
NEW 14.07.17 11:56 
в ответ Kvint 14.07.17 11:08

Можете просто скопировать и вставить текст. Или разместите ссылку на файлообменник, например Яндекс-Диск.

#26 
TUKL завсегдатай14.07.17 17:05
TUKL
NEW 14.07.17 17:05 
в ответ Kvint 05.07.17 22:27

Generic можно было бы использовать, если бы методы были одинаковые.

public interface TestInterface<T> {
public void a(T value);
}


public class TestImplA implements TestInterface<BigInteger> {


@Override

public void a(BigInteger value) { }

}


Но тут названия методов отличаются, в первом случае А, а во втором - B:

public class A implements TestInterface{
public A(BigInteger value){
System.out.println("This is A");
}
}

public class B implements TestInterface{
public B(BigDecimal value){
System.out.println("This is B");
}
}



Архитектура явно кривая, грубо нарушено Single Responsibility Rule, классы огромные итд. Необходимо разбить интерфейс на несколько, с использованием дженериков, выделить отдельные классы и так далее. Толку от использования общего интерфейса, если методы все равно разные, и по идее впоследствии в коде нужно будет делать проверки при их вызове в зависимости от аргумента?

TestInterface worker = TestInterfaceFactory.getTestInterface(value);

if (value instanceof BigInteger) {
worker.a(value);
} elseif (value instanceof BigDecimal) {
worker.b(value);
} else {
...


Но в любом разе решение - это фабрика:

public class TestInterfaceFactory {


public static TestInterface getInstance(Object value) {
if (value instanceof BigInteger) {
return new TestImplA();
} else if (value instanceof BigDecimal) {
return new TestImplB();
} else {
throw new IllegalArgumentException("unsopported value type");
}
}

}
#27 
Kvint постоялец15.07.17 12:04
Kvint
NEW 15.07.17 12:04 
в ответ TUKL 14.07.17 17:05

вот что я пока написал только для одного класса:

1) интерфейс


public interface NumberInterface {
public NumberInterface EMPTY();
public NumberInterface UNBOUND();
public NumberInterface BOOLEAN_INTERVAL();
public NumberInterface ZERO();
public NumberInterface ONE();

public boolean intersects(NumberInterface other);
public Number getLow();
public Number getHigh();
public boolean isGreaterThan(NumberInterface other);
public boolean isGreaterOrEqualThan(NumberInterface other);
public NumberInterface plus(NumberInterface interval);
public NumberInterface minus(NumberInterface other);
public NumberInterface times(NumberInterface other);
public NumberInterface divide(NumberInterface other);
public NumberInterface shiftLeft(NumberInterface offset);
public NumberInterface shiftRight(NumberInterface offset);
public NumberInterface modulo(NumberInterface other);
public boolean isUnbound();
public NumberInterface union(NumberInterface other) ;
public boolean contains(NumberInterface other);
public boolean isEmpty();
public NumberInterface negate();
// public NumberInterface createUpperBoundedInterval(Long upperBound);
// public NumberInterface createLowerBoundedInterval(Long lowerBound);
public NumberInterface intersect(NumberInterface other);
public NumberInterface limitUpperBoundBy(NumberInterface other);
public NumberInterface limitLowerBoundBy(NumberInterface other);
}

#28 
Kvint постоялец15.07.17 12:06
Kvint
NEW 15.07.17 12:06 
в ответ Kvint 15.07.17 12:04

класс который его имплеменитирует


public class IntegerInterval implements NumberInterface {
/**
* the lower bound of the interval
*/
private final Long low;



/**
* the upper bound of the interval
*/
private final Long high;



private static final IntegerInterval EMPTY = new IntegerInterval(null, null);
public static final IntegerInterval UNBOUND = new IntegerInterval(Long.MIN_VALUE, Long.MAX_VALUE);
public static final IntegerInterval BOOLEAN_INTERVAL = new IntegerInterval(0L, 1L);
public static final IntegerInterval ZERO = new IntegerInterval(0L, 0L);
public static final IntegerInterval ONE = new IntegerInterval(1L, 1L);



/**
* This method acts as constructor for a single-value interval.
*
* @param value
* for the lower and upper bound
*/
public IntegerInterval(Long value) {
this.low = value;



this.high = value;



isSane();
}



/**
* This method acts as constructor for a long-based interval.
*
* @param low
* the lower bound
* @param high
* the upper bound
*/
public IntegerInterval(Long low, Long high) {
this.low = low;



this.high = high;



isSane();
}



@Override
public NumberInterface EMPTY() {
return EMPTY;
}



@Override
public NumberInterface UNBOUND() {
return UNBOUND;
}



@Override
public NumberInterface BOOLEAN_INTERVAL() {
return BOOLEAN_INTERVAL;
}



@Override
public NumberInterface ZERO() {
return ZERO;
}



@Override
public NumberInterface ONE() {
return ONE;
}



private boolean isSane() {
if ((low == null) != (high == null)) {
throw new IllegalStateException("invalid empty interval");
}
if (low != null && low > high) {
throw new IllegalStateException("low cannot be larger than high");
}



return true;
}



/**
* This method returns the lower bound of the interval.
*
* @return the lower bound
*/
@Override
public Long getLow() {
return low;
}



/**
* This method returns the upper bound of the interval.
*
* @return the upper bound
*/
@Override
public Long getHigh() {
return high;
}



/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object other) {
if (other != null && getClass().equals(other.getClass())) {
IntegerInterval another = (IntegerInterval) other;
return Objects.equals(low, another.getLow()) && Objects.equals(high, another.getHigh());
}
return false;
}



/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Objects.hash(low, high);
}



/**
* This method creates a new interval instance representing the union of
* this interval with another interval.
*
* The lower bound and upper bound of the new interval is the minimum of
* both lower bounds and the maximum of both upper bounds, respectively.
*
* @param other
* the other interval
* @return the new interval with the respective bounds
*/
@Override
public NumberInterface union(NumberInterface other) {
IntegerInterval tempOther = (IntegerInterval)other;
if (isEmpty() || tempOther.isEmpty()) {
return EMPTY;
} else if (low <= other.getLow() && high >= other.getHigh()) {
return this;
} else if (low >= other.getLow() && high <= other.getHigh()) {
return other;
} else {
return new IntegerInterval(Math.min(low, other.getLow()), Math.max(high, other.getHigh()));
}
}



/**
* This method creates a new interval instance representing the intersection
* of this interval with another interval.
*
* The lower bound and upper bound of the new interval is the maximum of
* both lower bounds and the minimum of both upper bounds, respectively.
*
* @param other
* the other interval
* @return the new interval with the respective bounds
*/
@Override
public NumberInterface intersect(NumberInterface other) {
if (this.intersects(other)) {
return new IntegerInterval(Math.max(low, other.getLow()), Math.min(high, other.getHigh()));
} else {
return EMPTY;
}
}



/**
* This method determines if this interval is definitely greater than the
* other interval.
*
* @param other
* interval to compare with
* @return true if the lower bound of this interval is always strictly
* greater than the upper bound of the other interval, else false
*/
@Override
public boolean isGreaterThan(NumberInterface other) {
IntegerInterval tempOther = (IntegerInterval)other;
return !isEmpty() && !tempOther.isEmpty() && low > tempOther.getHigh();
}



/**
* This method determines if this interval is definitely greater or equal
* than the other interval. The equality is only satisfied for one single
* value!
*
* @param other
* interval to compare with
* @return true if the lower bound of this interval is always strictly
* greater or equal than the upper bound of the other interval, else
* false
*/
@Override
public boolean isGreaterOrEqualThan(NumberInterface other) {
IntegerInterval tempOther = (IntegerInterval)other;
return !isEmpty() && !tempOther.isEmpty() && low >= tempOther.getHigh();
}



/**
* This method determines if this interval maybe greater than the other
* interval.
*
* @param other
* interval to compare with
* @return true if the upper bound of this interval is strictly greater than
* the lower bound of the other interval, else false
*/
public boolean mayBeGreaterThan(IntegerInterval other) {
return other.isEmpty() || (!isEmpty() && !other.isEmpty() && high > other.getLow());
}



/**
* This method determines if this interval maybe greater or equal than the
* other interval.
*
* @param other
* interval to compare with
* @return true if the upper bound of this interval is strictly greater than
* the lower bound of the other interval, else false
*/
public boolean mayBeGreaterOrEqualThan(IntegerInterval other) {
return other.isEmpty() || (!isEmpty() && !other.isEmpty() && high >= other.getLow());
}



/**
* New interval instance after the modulo computation.
*
* @param other
* the other interval
* @return the new interval with the respective bounds.
*/
@Override
public NumberInterface modulo(NumberInterface other){
IntegerInterval tempOther = (IntegerInterval)other;
if (tempOther.contains(ZERO)) {
return IntegerInterval.UNBOUND;
}



// The interval doesn't contain zero, hence low and high has to be of
// the same sign.
// In that case we can call an absolute value on both, as "% (-x)" is
// the same as "% x".
other = new IntegerInterval(Math.abs(other.getLow()), Math.abs(other.getHigh()));



long newHigh;
long newLow;



// New high of the interval can't be higher than the highest value in
// the divisor.
// If the divisible element is positive, it is also bounded by it's
// highest number,
// or by the absolute value of the lowest number.
// (-1 % 6 CAN be either -1 or 5 according to the C standard).
long top;
if (low >= 0) {
top = high;
} else {
if (low == Long.MIN_VALUE) {
top = Long.MAX_VALUE;
} else {
top = Math.max(Math.abs(low), high);
}
}
newHigh = Math.min(top, other.getHigh() - 1);



// Separate consideration for the case where the divisible number can be
// negative.
if (low >= 0) { // If the divisible interval is all positive, the lowest
// we can ever get is 0.



// We can only get zero if we include 0 or the number higher than
// the smallest value of the other interval.
if (low == 0 || high >= other.getLow()) {
newLow = 0;
} else {
newLow = low;
}
} else {
// The remainder can go negative, but it can not be more negative
// than the negation of the highest value
// of the other interval plus 1.
// (e.g. X mod 14 can not be lower than -13)



// Remember, <low> is negative in this branch.
newLow = Math.max(low, 1 - other.getHigh());
}



IntegerInterval out = new IntegerInterval(newLow, newHigh);
return out;
}



/**
* This method returns a new interval with a limited, i.e. higher, lower
* bound.
*
* @param other
* the interval to limit this interval
* @return the new interval with the upper bound of this interval and the
* lower bound set to the maximum of this interval's and the other
* interval's lower bound or an empty interval if this interval is
* less than the other interval.
*/
@Override
public NumberInterface limitLowerBoundBy(NumberInterface other) {
IntegerInterval interval = null;



if (isEmpty() || other.isEmpty() || high < other.getLow()) {
interval = EMPTY;
} else {
interval = new IntegerInterval(Math.max(low, other.getLow()), high);
}



return interval;
}



/**
* This method returns a new interval with a limited, i.e. lower, upper
* bound.
*
* @param other
* the interval to limit this interval
* @return the new interval with the lower bound of this interval and the
* upper bound set to the minimum of this interval's and the other
* interval's upper bound or an empty interval if this interval is
* greater than the other interval.
*/
@Override
public NumberInterface limitUpperBoundBy(NumberInterface other) {
IntegerInterval interval = null;



if (isEmpty() || other.isEmpty() || low > other.getHigh()) {
interval = EMPTY;
} else {
interval = new IntegerInterval(low, Math.min(high, other.getHigh()));
}



return interval;
}



/**
* This method determines if this interval intersects with another interval.
*
* @param other
* the other interval
* @return true if the intervals intersect, else false
*/
@Override
public boolean intersects(NumberInterface other) {



if (isEmpty() || other.isEmpty()) {
return false;
}



return (low >= other.getLow() && low <= other.getHigh()) || (high >= other.getLow() && high <= other.getHigh())
|| (low <= other.getLow() && high >= other.getHigh());
}



/**
* This method determines if this interval contains another interval.
*
* The method still returns true, if the borders match. An empty interval
* does not contain any interval and is not contained in any interval
* either. So if the callee or parameter is an empty interval, this method
* will return false.
*
* @param other
* the other interval
* @return true if this interval contains the other interval, else false
*/
@Override
public boolean contains(NumberInterface other) {
IntegerInterval tempOther = (IntegerInterval)other;
return (!isEmpty() && !tempOther.isEmpty() && low <= other.getLow() && other.getHigh() <= high);
}



/**
* This method adds an interval from this interval, overflow is handled by
* setting the bound to Long.MIN_VALUE or Long.MAX_VALUE respectively.
*
* @param interval
* the interval to add
* @return a new interval with the respective bounds
*/
@Override
public NumberInterface plus(NumberInterface interval) {
IntegerInterval tempInterval = (IntegerInterval)interval;
if (isEmpty() || tempInterval.isEmpty()) {
return EMPTY;
}



return new IntegerInterval(scalarPlus(low, tempInterval.getLow()), scalarPlus(high, tempInterval.getHigh()));
}



/**
* This method adds a constant offset to this interval, overflow is handled
* by setting the bound to Long.MIN_VALUE or Long.MAX_VALUE respectively.
*
* @param offset
* the constant offset to add
* @return a new interval with the respective bounds
*/
public NumberInterface plus(Long offset) {
return plus(new IntegerInterval(offset, offset));
}



/**
* This method subtracts an interval from this interval, overflow is handled
* by setting the bound to Long.MIN_VALUE or Long.MAX_VALUE respectively.
*
* @param other
* interval to subtract
* @return a new interval with the respective bounds
*/
@Override
public NumberInterface minus(NumberInterface other) {
IntegerInterval tempOther = (IntegerInterval)other;
return plus(tempOther.negate());
}



/**
* This method subtracts a constant offset to this interval, overflow is
* handled by setting the bound to Long.MIN_VALUE or Long.MAX_VALUE
* respectively.
*
* @param offset
* the constant offset to subtract
* @return a new interval with the respective bounds
*/
public NumberInterface minus(Long offset) {
return plus(-offset);
}



/**
* This method multiplies this interval with another interval. In case of an
* overflow Long.MAX_VALUE and Long.MIN_VALUE are used instead.
*
* @param other
* interval to multiply this interval with
* @return new interval that represents the result of the multiplication of
* the two intervals
*/
@Override
public NumberInterface times(NumberInterface other) {

Long[] values = { scalarTimes(low, other.getLow()), scalarTimes(low, other.getHigh()),
scalarTimes(high, other.getLow()), scalarTimes(high, other.getHigh()) };



return new IntegerInterval(Collections.min(Arrays.asList(values)), Collections.max(Arrays.asList(values)));
}



/**
* This method divides this interval by another interval. If the other
* interval contains "0" an unbound interval is returned.
*
* @param other
* interval to divide this interval by
* @return new interval that represents the result of the division of the
* two intervals
*/
@Override
public NumberInterface divide(NumberInterface other) {
// other interval contains "0", return unbound interval
if (other.contains(ZERO)) {
return UNBOUND;
} else {
Long[] values = { low / other.getLow(), low / other.getHigh(), high / other.getLow(),
high / other.getHigh() };



return new IntegerInterval(Collections.min(Arrays.asList(values)), Collections.max(Arrays.asList(values)));
}
}



/**
* This method performs an arithmetical left shift of the interval bounds.
*
* @param offset
* Interval offset to perform an arithmetical left shift on the
* interval bounds. If the offset maybe less than zero an unbound
* interval is returned.
* @return new interval that represents the result of the arithmetical left
* shift
*/
@Override
public NumberInterface shiftLeft(NumberInterface offset) {
// create an unbound interval upon trying to shift by a possibly
// negative offset
IntegerInterval tempOffset = (IntegerInterval)offset;
if (ZERO.mayBeGreaterThan(tempOffset)) {
return UNBOUND;
} else {
// if lower bound is negative, shift it by upper bound of offset,
// else by lower bound of offset
Long newLow = low << ((low < 0L) ? offset.getHigh() : offset.getLow());



// if upper bound is negative, shift it by lower bound of offset,
// else by upper bound of offset
Long newHigh = high << ((high < 0L) ? offset.getLow() : offset.getHigh());



if ((low < 0 && newLow > low) || (high > 0 && newHigh < high)) {
return UNBOUND;
} else {
return new IntegerInterval(newLow, newHigh);
}
}
}



/**
* This method performs an arithmetical right shift of the interval bounds.
* If the offset maybe less than zero an unbound interval is returned.
*
* @param offset
* Interval offset to perform an arithmetical right shift on the
* interval bounds
* @return new interval that represents the result of the arithmetical right
* shift
*/
@Override
public NumberInterface shiftRight(NumberInterface offset) {
// create an unbound interval upon trying to shift by a possibly
// negative offset
IntegerInterval tempOffset = (IntegerInterval)offset;
if (ZERO.mayBeGreaterThan(tempOffset)) {
return UNBOUND;
} else {
// if lower bound is negative, shift it by lower bound of offset,
// else by upper bound of offset
Long newLow = low >> ((low < 0L) ? offset.getLow() : offset.getHigh());



// if upper bound is negative, shift it by upper bound of offset,
// else by lower bound of offset
Long newHigh = high >> ((high < 0L) ? offset.getHigh() : offset.getLow());



return new IntegerInterval(newLow, newHigh);
}
}



/**
* This method negates this interval.
*
* @return new negated interval
*/
@Override
public NumberInterface negate() {
return new IntegerInterval(scalarTimes(high, -1L), scalarTimes(low, -1L));
}



/**
* This method determines whether the interval is empty or not.
*
* @return true, if the interval is empty, i.e. the lower and upper bounds
* are null
*/
@Override
public boolean isEmpty() {
return low == null && high == null;
}
@Override
public boolean isUnbound() {
return !isEmpty() && low == Long.MIN_VALUE && high == Long.MAX_VALUE;
}



/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "[" + (low == null ? "" : low) + "; " + (high == null ? "" : high) + "]";
}



/**
* This method is a factory method for a lower bounded interval.
*
* @param lowerBound
* the lower bound to set
* @return a lower bounded interval, i.e. the lower bound is set to the
* given lower bound, the upper bound is set to Long.MAX_VALUE
*/



public static NumberInterface createLowerBoundedInterval(Long lowerBound) {
return new IntegerInterval(lowerBound, Long.MAX_VALUE);
}



/**
* This method is a factory method for an upper bounded interval.
*
* @param upperBound
* the upper bound to set
* @return an upper bounded interval, i.e. the lower bound is set to
* Long.MIN_VALUE, the upper bound is set to the given upper bound
*/



public static NumberInterface createUpperBoundedInterval(Long upperBound) {
return new IntegerInterval(Long.MIN_VALUE, upperBound);
}



/**
* This method adds two scalar values and returns their sum, or on overflow
* Long.MAX_VALUE or Long.MIN_VALUE, respectively.
*
* @param x
* the first scalar operand
* @param y
* the second scalar operand
* @return the sum of the first and second scalar operand or on overflow
* Long.MAX_VALUE and Long.MIN_VALUE, respectively.
*/
private static Long scalarPlus(Long x, Long y) {
Long result = x + y;



// both operands are positive but the result is negative
if ((Long.signum(x) + Long.signum(y) == 2) && Long.signum(result) == -1) {
result = Long.MAX_VALUE;
} else if ((Long.signum(x) + Long.signum(y) == -2) && Long.signum(result) == +1) {
result = Long.MIN_VALUE;
}



return result;
}



/**
* This method multiplies two scalar values and returns their product, or on
* overflow Long.MAX_VALUE or Long.MIN_VALUE, respectively.
*
* @param x
* the first scalar operand
* @param y
* the second scalar operand
* @return the product of the first and second scalar operand or on overflow
* Long.MAX_VALUE and Long.MIN_VALUE, respectively.
*/
private static Long scalarTimes(Long x, Long y) {
Long bound = (Long.signum(x) == Long.signum(y)) ? Long.MAX_VALUE : Long.MIN_VALUE;



// if overflow occurs, return the respective bound
if (x != 0 && ((y > 0 && y > (bound / x)) || (y < 0 && y < (bound / x)))) {
return bound;
} else {
return x * y;
}
}
}

#29 
Kvint постоялец15.07.17 12:10
Kvint
NEW 15.07.17 12:10 
в ответ Kvint 15.07.17 12:06

class ExpressionValueVisitor extends DefaultCExpressionVisitor<NumberInterface, UnrecognizedCCodeException>
implements CRightHandSideVisitor<NumberInterface, UnrecognizedCCodeException> {



private final IntervalAnalysisState readableState;



private final CFAEdge cfaEdge;



public ExpressionValueVisitor(IntervalAnalysisState pState, CFAEdge edge) {
readableState = pState;
cfaEdge = edge;
}



@Override
protected NumberInterface visitDefault(CExpression expression) {
return new CreatorIntegerInterval().factoryMethod(null).UNBOUND();
}



@Override
public NumberInterface visit(CBinaryExpression binaryExpression) throws UnrecognizedCCodeException {
NumberInterface interval1 = binaryExpression.getOperand1().accept(this);
NumberInterface interval2 = binaryExpression.getOperand2().accept(this);



if (interval1 == null || interval2 == null) {
return new CreatorIntegerInterval().factoryMethod(null).UNBOUND();
}



BinaryOperator operator = binaryExpression.getOperator();
if (operator.isLogicalOperator()) {
return getLogicInterval(operator, interval1, interval2);
} else {
return getArithmeticInterval(operator, interval1, interval2);
}
}



private static NumberInterface getLogicInterval(
BinaryOperator operator, NumberInterface interval1, NumberInterface interval2) {
switch (operator) {
case EQUALS:
if (!interval1.intersects(interval2)) {
return new CreatorIntegerInterval().factoryMethod(null).ZERO();
} else if (interval1.getLow().equals(interval1.getHigh()) && interval1.equals(interval2)) {
// singular interval, [5;5]==[5;5]
return new CreatorIntegerInterval().factoryMethod(null).ONE();
} else {
return new CreatorIntegerInterval().factoryMethod(null).BOOLEAN_INTERVAL();
}



case NOT_EQUALS:
if (!interval1.intersects(interval2)) {
return new CreatorIntegerInterval().factoryMethod(null).ONE();
} else if (interval1.getLow().equals(interval1.getHigh()) && interval1.equals(interval2)) {
// singular interval, [5;5]!=[5;5]
return new CreatorIntegerInterval().factoryMethod(null).ZERO();
} else {
return new CreatorIntegerInterval().factoryMethod(null).BOOLEAN_INTERVAL();
}



case GREATER_THAN:
if (interval1.isGreaterThan(interval2)) {
return new CreatorIntegerInterval().factoryMethod(null).ONE();
} else if (interval2.isGreaterOrEqualThan(interval1)) {
return new CreatorIntegerInterval().factoryMethod(null).ZERO();
} else {
return new CreatorIntegerInterval().factoryMethod(null).BOOLEAN_INTERVAL();
}



case GREATER_EQUAL: // a>=b == a+1>b, works only for integers
return getLogicInterval(
BinaryOperator.GREATER_THAN, interval1.plus(new CreatorIntegerInterval().factoryMethod(null).ONE()), interval2);



case LESS_THAN: // a<b == b>a
return getLogicInterval(BinaryOperator.GREATER_THAN, interval2, interval1);



case LESS_EQUAL: // a<=b == b+1>a, works only for integers
return getLogicInterval(
BinaryOperator.GREATER_THAN, interval2.plus(new CreatorIntegerInterval().factoryMethod(null).ONE()), interval1);



default:
throw new AssertionError("unknown binary operator: " + operator);
}
}



private static NumberInterface getArithmeticInterval(
BinaryOperator operator, NumberInterface interval1, NumberInterface interval2) {
switch (operator) {
case PLUS:
return interval1.plus(interval2);
case MINUS:
return interval1.minus(interval2);
case MULTIPLY:
return interval1.times(interval2);
case DIVIDE:
return interval1.divide(interval2);
case SHIFT_LEFT:
return interval1.shiftLeft(interval2);
case SHIFT_RIGHT:
return interval1.shiftRight(interval2);
case MODULO:
return interval1.modulo(interval2);
case BINARY_AND:
case BINARY_OR:
case BINARY_XOR:
return new CreatorIntegerInterval().factoryMethod(null).UNBOUND();
default:
throw new AssertionError("unknown binary operator: " + operator);
}
}



@Override
public NumberInterface visit(CCastExpression cast) throws UnrecognizedCCodeException {
return cast.getOperand().accept(this);
}



@Override
public NumberInterface visit(CFunctionCallExpression functionCall) {
return new CreatorIntegerInterval().factoryMethod(null).UNBOUND();
}



@Override
public NumberInterface visit(CCharLiteralExpression charLiteral) {
return new CreatorIntegerInterval().factoryMethod((long) charLiteral.getCharacter());
}



@Override
public NumberInterface visit(CImaginaryLiteralExpression exp) throws UnrecognizedCCodeException {
return exp.getValue().accept(this);
}



@Override
public NumberInterface visit(CIntegerLiteralExpression integerLiteral) {
//TODO BigInteger
return new CreatorIntegerInterval().factoryMethod(integerLiteral.asLong());
}


@Override
public NumberInterface visit(CFloatLiteralExpression integerLiteral) {
//TODO BigDecimal
return new CreatorIntegerInterval().factoryMethod(integerLiteral.getValue().longValue());
}



@Override
public NumberInterface visit(CIdExpression identifier) {
if (identifier.getDeclaration() instanceof CEnumerator) {
//TODO WTF
return new CreatorIntegerInterval().factoryMethod(((CEnumerator) identifier.getDeclaration()).getValue());///???
}



final String variableName = identifier.getDeclaration().getQualifiedName();
if (readableState.contains(variableName)) {
return readableState.getInterval(variableName);
} else {
return new CreatorIntegerInterval().factoryMethod(null).UNBOUND();
}
}



@Override
public NumberInterface visit(CUnaryExpression unaryExpression) throws UnrecognizedCCodeException {
NumberInterface interval = unaryExpression.getOperand().accept(this);
switch (unaryExpression.getOperator()) {
case MINUS:
return interval.negate();



case AMPER:
case TILDE:
return new CreatorIntegerInterval().factoryMethod(null).UNBOUND(); // valid expression, but it's a pointer value



default:
throw new UnrecognizedCCodeException("unknown unary operator", cfaEdge, unaryExpression);
}
}
}

а вот собственно класс который вызывает интерфейс. таких классов три, каждый что то свое вызывает. в данном случае интервалы



#30 
AlexNek патриот15.07.17 13:28
AlexNek
NEW 15.07.17 13:28 
в ответ Kvint 15.07.17 12:10

Тут есть тэг pre. Только надо в режиме прямого редактирования всё вносить

<pre>исходник</pre>


Ну и длинные простыни воспринимать весьма затруднительно, лучше как приложение сжелать.

#31 
AlexNek патриот15.07.17 13:43
AlexNek
NEW 15.07.17 13:43 
в ответ Kvint 15.07.17 12:04

Как там у вас я Яве принято не знаю.

Но константантам в интерфейсе по идее нечего делать.

public NumberInterface EMPTY(); 
public NumberInterface UNBOUND();
public NumberInterface BOOLEAN_INTERVAL();
public NumberInterface ZERO();
public NumberInterface ONE();

ну и не принято вроде, чтобы IsXxxx выбрасывала исключение.

#32 
Kvint постоялец15.07.17 14:44
Kvint
NEW 15.07.17 14:44 
в ответ AlexNek 15.07.17 13:43

это не константы, это методы, которые возвращают константы. тоже не совсем понятно как их прописать, в самом интерфейсе или оставить так.

#33 
1 2 все